精华内容
下载资源
问答
  • 动态加载 dubbo spring

    2018-02-02 11:00:00
    动态加载 dubbo spring 1.首先删除 配置文件中 dubboservice ,以及 项目中引用 service,然后 删除entity 中user,以及...-- 生成远程服务代理,可以和本地bean一样使用demoService --> <!-- <dubbo:r...

    动态加载 dubbo spring

     

    1.首先删除 配置文件中 dubboservice ,以及 项目中引用 service,然后 删除entity 中user,以及service 中userservice

    <!-- 生成远程服务代理,可以和本地bean一样使用demoService -->
    <!-- <dubbo:reference id="userService"  interface="com.curiousby.cn.service.UserService" /> -->

     



     

     

     

    2. usercontroller中修改代码

      
        @RequestMapping(value="/auto/{userId}", method=RequestMethod.GET)
        public Object  getUserById2(@PathVariable int userId) throws  Exception {
        	 String url = "dubbo://localhost:20880/com.curiousby.cn.service.UserService";//更改不同的Dubbo服务暴露的ip地址&端口  
        	 //dubbo%3A%2F%2F10.133.254.143%3A20880%2Fcom.curiousby.cn.service.UserService%3Fanyhost%3Dtrue%26application%3Ddubbox-productor%26dubbo%3D2.5.3%26interface%3Dcom.curiousby.cn.service.UserService%26methods%3DfindById%26pid%3D14284%26side%3Dprovider%26timestamp%3D1517473747502
        	 
        	 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();  
        	 URL  classesurl = new URL( "file:///D:/cache/eclipse4mvn-workplace/SpringBootDubboxDemo-Consumer/target/classes/com/curiousby/cn/" );  
        	 ClassLoader custom = new URLClassLoader( new URL[] { classesurl }, systemClassLoader ); 
        	 
        	 //Class  myClazz =   Class.forName("com.curiousby.cn.service.UserService");
        	 Class myClazz = custom.loadClass("com.curiousby.cn.service.UserService"); 
        	   
        	 List classList = new ArrayList();
        	 List valList = new ArrayList();
        	 classList.add(Class.forName("java.lang.Integer"));
        	 valList.add(userId);
        	 
        	 ReferenceBean referenceBean = new ReferenceBean();  
             referenceBean.setApplicationContext(applicationContext);  
             referenceBean.setInterface(myClazz);  
             referenceBean.setUrl(url);  
       
             try {  
                 referenceBean.afterPropertiesSet();  
                 Object object = referenceBean.get(); 
                  
                 Method  methodService = myClazz.getMethod("findById", (Class[])classList.toArray(new Class[0]));
                 return methodService.invoke(object, valList.toArray());
             } catch (Exception e) {  
                 e.printStackTrace();  
             }
    		return null;  
        }

     

     

    3.上传 class 文件到指定位置



     



     

     

     

    这样就可以按照配置,自动上传 class 并解析 消费服务了



     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    捐助开发者 

    在兴趣的驱动下,写一个免费的东西,有欣喜,也还有汗水,希望你喜欢我的作品,同时也能支持一下。 当然,有钱捧个钱场(支持支付宝和微信 以及扣扣群),没钱捧个人场,谢谢各位。

     

    个人主页http://knight-black-bob.iteye.com/



     
     
     谢谢您的赞助,我会做的更好!

     

     

     

     

     

    展开全文
  • 对Dobbo中的动态生成类进行了描述,包括:(1)自适应机制中的Adaptive动态类、(2)服务引用的proxy接口代理类、(3)Wrapper包装类


    Dubbo中的动态生成类体现在如下几个方面:1. 自适应扩展机制中的Adaptive类;2. 服务引用的接口代理类;3. 方便获取类信息的Wrapper。他们具有不同的作用,下面逐一分析。

    自适应扩展机制中的Adaptive类

    自适应扩展机制是Dubbo对SPI机制(Service Provider Interface)的增强实现版,和API相比,在使用SPI时,调用方无需指定接口的具体实现,而在程序运行时决定。

    自适应扩展机制说明

    和原生SPI一样,在Dubbo的自适应扩展机制中,用META-INF目录下的配置文件指定接口实现类,配置文件名为接口的全限定类名。如下图,在dubbo-cluster包下的META-INF目录下,配置文件com.alibaba.dubbo.rpc.cluster.LoadBalance指定了四个接口实现,等号左边是实现类的name,等号右边是实现类的全限定类名。

    // dubbo-cluster包中的配置文件com.alibaba.dubbo.rpc.cluster.LoadBalance
    random=com.alibaba.dubbo.rpc.cluster.loadbalance.RandomLoadBalance
    roundrobin=com.alibaba.dubbo.rpc.cluster.loadbalance.RoundRobinLoadBalance
    leastactive=com.alibaba.dubbo.rpc.cluster.loadbalance.LeastActiveLoadBalance
    consistenthash=com.alibaba.dubbo.rpc.cluster.loadbalance.ConsistentHashLoadBalance
    

    在Dubbo中,自适应扩展机制主要由类ExtensionLoader实现,对于接口T(本例中的LoadBalance),ExtensionLoader提供getAdaptiveExtension()方法,返回接口T的自适应实现类实例,该类实现了接口T,作为所有其它接口T实现类的入口。在对接口T中注解了@Adaptive的方法进行调用时,自适应实现类实例根据调用方法的参数获取实现类的name,并调用getExtension(String name)获取相应类实例,使用相应方法完成调用。
    在上面的例子中,调用通过自适应类的接口方法select时,如果参数url中关于负载均衡的参数使用了"roundrobin",那么自适应实现类对象会获取到RoundRobinLoadBalance的实例,并通过该实例调用select方法,实现特定的负载均衡策略。

    @SPI(RandomLoadBalance.NAME)
    public interface LoadBalance {
        @Adaptive("loadbalance")
        <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException;
    }
    

    Adaptive类实现自适应

    如上所述,Dubbo中的自适应扩展机制是通过ExtensionLoader<T>类实现的,其中,T是SPI接口,ExtensionLoader<T>提供getAdaptiveExtension()方法,该方法返回一个自适应实现类的实例。这个自适应类可以是预先定义的,也可以是动态生成的。这里先认为这个自适应类是动态生成的,这符合大部分的场景,预定义实现类的情况将在下一节会详细描述。把这个动态生成的自适应类记为T$Adaptive,它是接口T的一个实现,作为接口T所有其它实现类的入口,完成了根据运行时动态传递的参数决定采用不同实现类实例的功能,是Dubbo实现SPI的关键点。下面举例说明

    package com.alibaba.dubbo.rpc;
    import com.alibaba.dubbo.common.extension.ExtensionLoader;
    public class Protocol$Adaptive implements com.alibaba.dubbo.rpc.Protocol {
        public void destroy() {throw new UnsupportedOperationException("method public abstract void com.alibaba.dubbo.rpc.Protocol.destroy() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
        }
        public int getDefaultPort() {throw new UnsupportedOperationException("method public abstract int com.alibaba.dubbo.rpc.Protocol.getDefaultPort() of interface com.alibaba.dubbo.rpc.Protocol is not adaptive method!");
        }
        public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws com.alibaba.dubbo.rpc.RpcException {
            if (arg1 == null) throw new IllegalArgumentException("url == null");
            com.alibaba.dubbo.common.URL url = arg1;
            String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
            if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
            com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
            return extension.refer(arg0, arg1);
        }
        public com.alibaba.dubbo.rpc.Exporter export(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
            if (arg0 == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
            if (arg0.getUrl() == null) throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");com.alibaba.dubbo.common.URL url = arg0.getUrl();
            String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
            if(extName == null) throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
            com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol)ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
            return extension.export(arg0);
        }
    }	
    

    上面给出了一个T$Adaptive类的例子,该例中接口T为Protocol,Protocol$Adaptive实现了export和refer两个接口方法,实现的思路都是从export和refer的接口参数中获取Dubbo URL,然后根据URL中动态传递的protocol参数确定应用的Protocol实现类name,通过ExtensionLoader<T>的getExtension(String name)方法获取该实现类的实例,调用具体实现类的export和refer方法。下面贴出了Protocol接口的定义代码,其中,注解@SPI(“dubbo”)表示该接口为一个SPI,并且默认实现类名称为dubbo;export和refer上的注解@Adaptive表示在增强类T$Adaptive的代码中实现这两个方法,没有注解@Adaptive的方法就不实现。

    @SPI("dubbo")
    public interface Protocol {
        int getDefaultPort();
        @Adaptive
        <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;
        @Adaptive
        <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;
        void destroy();
    }
    

    ExtensionLoader<T>的getExtension(String name)方法代码贴出如下,ExtensionLoader<T>先到缓存cachedInstances中看有没有name对应类的实例,有就直接返回,没有则调用createExtension(String name)创建一个。

        // ExtensionLoader
        public T getExtension(String name) {
            ...
            // 从缓存取, cachedInstances的key是类对应的name,value是实例
            Holder<Object> holder = cachedInstances.get(name);
            if (holder == null) {
                cachedInstances.putIfAbsent(name, new Holder<Object>());
                holder = cachedInstances.get(name);
            }
            Object instance = holder.get();
            if (instance == null) {
                synchronized (holder) {
                    instance = holder.get();
                    if (instance == null) {
                        // 缓存没有创建一个
                        instance = createExtension(name);
                        holder.set(instance);
                    }
                }
            }
            return (T) instance;
        }
    

    createExtension(String name)代码如下,首先调用getExtensionClasses().get(name)获取名为name的类定义,然后以类定义为key从缓存EXTENSION_INSTANCES中取实例,有则返回,没有则创建一个,并用包裹类进行包裹。

        // ExtensionLoader
        private T createExtension(String name) {
            // 取类定义
            Class<?> clazz = getExtensionClasses().get(name);
            if (clazz == null) {
                throw findException(name);
            }
            try {
                // 从缓存取, EXTENSION_INSTANCES的key是类定义,value是实例
                // EXTENSION_INSTANCES 和 cachedInstances 都是实例的缓存,但是key不一样
                // dubbo的spi配置文件中,多个name可能对应同一个实现类的定义
                T instance = (T) EXTENSION_INSTANCES.get(clazz);
                if (instance == null) {
                    EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                    instance = (T) EXTENSION_INSTANCES.get(clazz);
                }
                injectExtension(instance);
                // 用包裹类嵌套
                Set<Class<?>> wrapperClasses = cachedWrapperClasses;
                if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                    for (Class<?> wrapperClass : wrapperClasses) {
                        instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                    }
                }
                return instance;
            } catch (Throwable t) {
                throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                        type + ")  could not be instantiated: " + t.getMessage(), t);
            }
        }
    

    在getExtensionClasses中,根据指定的接口类型,扫描"META-INF/services/"、“META-INF/dubbo/”、"META-INF/dubbo/internal/"三个目录下关于该接口的实现类,加载到ExtensionLoader的成员cachedClasses中并返回,代码片段如下

        // ExtensionLoader
        private Map<String, Class<?>> getExtensionClasses() {
            Map<String, Class<?>> classes = cachedClasses.get();
            if (classes == null) {
                synchronized (cachedClasses) {
                    classes = cachedClasses.get();
                    if (classes == null) {
                        classes = loadExtensionClasses();
                        // 加载到cachedClasses
                        cachedClasses.set(classes);
                    }
                }
            }
            return classes;
        }
    
        // ExtensionLoader
        private Map<String, Class<?>> loadExtensionClasses() {
            ......
            Map<String, Class<?>> extensionClasses = new HashMap<String, Class<?>>();
            // 扫描META-INF/dubbo/internal/
            loadDirectory(extensionClasses, DUBBO_INTERNAL_DIRECTORY);
            // 扫描META-INF/dubbo/
            loadDirectory(extensionClasses, DUBBO_DIRECTORY);
            // 扫描META-INF/services/
            loadDirectory(extensionClasses, SERVICES_DIRECTORY);
            return extensionClasses;
        }
    

    综上所述,对于接口T,ExtensionLoader提供getAdaptiveExtension()方法,返回动态生成类T$Adaptive的实例,T$Adaptive实现了接口T,作为所有其它接口T实现类的入口,在对接口T中注解了@Adaptive的方法进行调用时,T$Adaptive的实现根据参数调用getExtension (String name)获取相应类的实例,调用相应实现方法完成调用。

    SPI实现类的类型

    Dubbo的自适应扩展机制中,把SPI的实现类分为三类:

    • 自适应实现类:如果接口T有自适实现类的实现,那么上述ExtensionLoader<T>的getAdaptiveExtension()方法直接返回自适应类的实例,而不会动态生成T$Adaptive类。通过Dubbo中定义的注解,可以表示自适应类,例如,接口ExtensionFactory实现AdaptiveExtensionFactory具有注解@Adapitve,它是一个自适应类。
    @Adaptive
    public class AdaptiveExtensionFactory implements ExtensionFactory {
          ...
    }
    
    • 包裹类:在上述的ExtensionLoader<T>的getExtension(String name)方法中,生成name对应实现类的实例时(注意这个name不是类名,而是SPI配置文件中的key),会用包裹类逐一包裹,最后得到的实际上是经过层层包裹的实例。包裹类是通过是否具有构造函数来判断的,例如,Protocol的实现ProtocolListenerWrapper是一个包裹类,它具有构造函数,因此是一个包裹类。ProtocolListenerWrapper的内部对象protocol是用来存放被包裹的对象的;ProtocolListenerWrapper实现了接口方法export和refer,并进行了增强实现,在本例中ProtocolListenerWrapper进行了增加监听器的增强实现。
    public class ProtocolListenerWrapper implements Protocol {
        private final Protocol protocol;
        public ProtocolListenerWrapper(Protocol protocol) {
            if (protocol == null) {
                throw new IllegalArgumentException("protocol == null");
            }
            this.protocol = protocol;
        }
        
        @Override
        public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
            if (Constants.REGISTRY_PROTOCOL.equals(invoker.getUrl().getProtocol())) {
                return protocol.export(invoker);
            }
            return new ListenerExporterWrapper<T>(protocol.export(invoker),
                    Collections.unmodifiableList(ExtensionLoader.getExtensionLoader(ExporterListener.class)
                            .getActivateExtension(invoker.getUrl(), Constants.EXPORTER_LISTENER_KEY)));
        }
    
        @Override
        public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
            if (Constants.REGISTRY_PROTOCOL.equals(url.getProtocol())) {
                return protocol.refer(type, url);
            }
            return new ListenerInvokerWrapper<T>(protocol.refer(type, url),
                    Collections.unmodifiableList(
                            ExtensionLoader.getExtensionLoader(InvokerListener.class)
                                    .getActivateExtension(url, Constants.INVOKER_LISTENER_KEY)));
        }
    
    • 普通实现类:接口T的一般实现类,是功能实现的基本内容。一般使用ExtensionLoader的getExtension(name)方法获取实现类实例。普通类型的实现类可以用@Activate注解进行标注。@Activate注解指定两个必须的值,group和value。ExtensionLoader提供方法getActivateExtension获取多个标注了@Activate的实现类实例。该方法如下:group传入要匹配的组,和实现类@Activate注解里的group匹配,如果匹配上,且url里的参数parameters的key包含@Activate注解的value值(类似于parameters.keyset().contains(value)的意思),则返回列表中包含该实现类;根据key在url的parameters参数取值(parameters.get(key)),根据取值获取希望返回的实现类name列表,根据这些name调用ExtensionLoader的getExtension(name)方法获取实现类实例。
        public List<T> getActivateExtension(URL url, String key, String group) {
            String value = url.getParameter(key);
            return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
        }
    

    在上面三种类型的实现类中:(1)在无法以固定模式动态生成接口T的自适应类T$Adaptive时,需要实现自适应实现类;(2)Wrap包裹类用于对接口实现类的功能进行增强,并不会通过getExtension(String name)接口直接获取;(3)普通实现类是基本功能的实现类,通过getExtension(String name)接口直接获取获取其实例,其中关于@Activate注解的用法可以参看Filter接口以及其实现类。

    重要数据结构

    public class ExtensionLoader<T> {
        // 接口T的类型
        private final Class<?> type;
        // 包裹类缓存,只保存包裹类型的实现类
        private Set<Class<?>> cachedWrapperClasses;
        // 自适应类缓存,只保存自适应类型的实现类,最多只能有一个
        private volatile Class<?> cachedAdaptiveClass = null;      
        // 自适应类实例缓存,只保存自适应类型的实现类实例,最多只能有一个
        private final Holder<Object> cachedAdaptiveInstance = new Holder<Object>();
        // 实现类名称缓存,key为实现类的类型,value为实现类的name,只保存普通类型的实现类名称
        private final ConcurrentMap<Class<?>, String> cachedNames = new ConcurrentHashMap<Class<?>, String>();               
        // 实现类缓存,key为实现类的name,value为实现类,只保存普通类型的实现类
        private final Holder<Map<String, Class<?>>> cachedClasses = new Holder<Map<String, Class<?>>>();     
        // cachedInstances是实现类实例缓存,key为实现类的名称,value为实例,只有普通类型的实现类才会产生实例
        // EXTENSION_INSTANCES是实现类实例缓存,key为实现类的类型,value为实例,只有普通类型的实现类才会产生实例
        // cachedInstances和EXTENSION_INSTANCES相比,因为多个name可能对应到同一个实现类,所以cachedInstances应该比EXTENSION_INSTANCES多
        // cachedInstances中的多个value可能在EXTENSION_INSTANCES中是同一个value
        private final ConcurrentMap<String, Holder<Object>> cachedInstances = new ConcurrentHashMap<String, Holder<Object>>();        
        private static final ConcurrentMap<Class<?>, Object> EXTENSION_INSTANCES = new ConcurrentHashMap<Class<?>, Object>();
        // Activate注解缓存
        private final Map<String, Activate> cachedActivates = new ConcurrentHashMap<String, Activate>();
        // 默认实现类名称,只能是普通类型的实现类
        private String cachedDefaultName;    
               
    }
    

    服务引用中的接口代理类

    服务引用的实现

    Dubbo对服务的引用是通过接口代理类实现的。

    <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService"/>
    

    例如,按照上面xml进行配置,Dubbo会动态生成一个DemoService的接口代理类proxy0,该代理类的成员handler完成对所引用的实际服务的调用,包括本地调用和远程调用。同时,该代理类proxy0还实现了其它一些扩展接口,这些接口的也都通过handler的invoke方法实现。

    public class proxy0 implements ClassGenerator.DC, EchoService, DemoService {
        public static Method[] methods;
        private InvocationHandler handler;
        public proxy0(InvocationHandler invocationHandler) {
            this.handler = invocationHandler;
        }
        public proxy0() {
        }
        public String sayHello(String string) {
            // 将参数存储到 Object 数组中
            Object[] arrobject = new Object[]{string};
            // 调用 InvocationHandler 实现类的 invoke 方法得到调用结果
            Object object = this.handler.invoke(this, methods[0], arrobject);
            // 返回调用结果
            return (String)object;
        }
        /** 回声测试方法 */
        public Object $echo(Object object) {
            Object[] arrobject = new Object[]{object};
            Object object2 = this.handler.invoke(this, methods[1], arrobject);
            return object2;
        }
    }
    

    如下给出了InvocationHandler的完整定义,InvocationHandler中包含一个成员invoker,invoker是对最终调用接口DemoService的层层封装,通过这些封装,可以完成额外的工作,包括上述扩展接口的功能。

    public class InvokerInvocationHandler implements InvocationHandler {
        private final Invoker<?> invoker;
        public InvokerInvocationHandler(Invoker<?> handler) {
            this.invoker = handler;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            ...
            return invoker.invoke(new RpcInvocation(method, args)).recreate();
        }
    }
    

    动态生成接口代理类的过程

    下面贴出了生成接口代理类的代码

        // JavassistProxyFactory
        public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
            return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
        }
    

    首先看一下Proxy,Proxy的代码贴出如下,Proxy是一个抽象类:它有一个抽象方法newInstance,和一个静态方法getProxy。getProxy实际返回一个Proxy子类的实例,该子类实现了抽象方法newInstance。因此,上面JavassistProxyFactory中生成接口代理类实例的getProxy方法可以看做分为两步实现:第一步调用Proxy.getProxy(interfaces)得到一个Proxy子类的实例,这个Proxy子类是动态生成的;第二步调用子类实例的newInstance方法得到接口代理类实例,这个接口代理类也是动态生成的。

    // Proxy 
    public abstract class Proxy {
        ...
        public static Proxy getProxy(ClassLoader cl, Class<?>... ics) {...}
        ...
        abstract public Object newInstance(InvocationHandler handler);
        ... 
    }
    

    重要数据结构

    public abstract class Proxy {
        ...
        // Proxy的子类缓存
        // 第一级Map的key是类加载器
        // 第二级Map的key是接口字符串,例如"com.alibaba.dubbo.demo.DemoService;com.alibaba.dubbo.rpc.service.EchoService;"
        // 第二级Map的可以理解为,可以生成某些接口代理类的Proxy子类
        private static final Map<ClassLoader, Map<String, Object>> ProxyCacheMap = new WeakHashMap<ClassLoader, Map<String, Object>>();
        ...
    }
    
    

    方便获取类信息的Wrapper

    抽象Wrapper类提供静态方法makeWrapper,该静态方法返回一个Wrapper子类的实例,该子类是动态生成的,它实现了Wrapper的抽象方法,通过这些抽象方法,可以方便获取类c的各种属性,也可以对c的方法进行反射调用。

    // Wrapper
    private static Wrapper makeWrapper(Class<?> c){
    ...
    }
    

    下面是Wrapper的抽象方法

    public abstract class Wrapper {
        abstract public String[] getPropertyNames();
        abstract public Class<?> getPropertyType(String pn);
        abstract public boolean hasProperty(String name);
        abstract public Object getPropertyValue(Object instance, String pn) throws NoSuchPropertyException, IllegalArgumentException;
        abstract public void setPropertyValue(Object instance, String pn, Object pv) throws NoSuchPropertyException, IllegalArgumentException;
        abstract public String[] getMethodNames();
        abstract public String[] getDeclaredMethodNames();
        abstract public Object invokeMethod(Object instance, String mn, Class<?>[] types, Object[] args) throws NoSuchMethodException, InvocationTargetException;
    }
    

    版本

    本文参考Dubbo2.6.8版本

    展开全文
  • Dubbo使用javassist生成动态类 在服务(本地和远程)暴露的时候会调用proxyFactory.getInvoker方法 具体位置: 本地暴露:ServiceConfig#exportLocal line:538 远程暴露: ServiceConfig#doExportUrlsFor1Protocol ...

    Dubbo使用javassist生成动态类

    在服务(本地和远程)暴露的时候会调用proxyFactory.getInvoker方法

    具体位置:

    • 本地暴露:ServiceConfig#exportLocal line:538
    • 远程暴露: ServiceConfig#doExportUrlsFor1Protocol line:512

    会先调用AOP织入的类StubProxyFactoryWrapper#getInvoker

    然后执行JavassistProxyFactory#getInvoker

    JavassistProxyFactory#getInvoker如下

    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) {
        // getWrapper会生成代理类
        final Wrapper wrapper = Wrapper.getWrapper(proxy.getClass().getName().indexOf('$') < 0 ? proxy.getClass() : type);
        return new AbstractProxyInvoker<T>(proxy, type, url) {
            @Override
            protected Object doInvoke(T proxy, String methodName,
                                      Class<?>[] parameterTypes,
                                      Object[] arguments) throws Throwable {
                return wrapper.invokeMethod(proxy, methodName, parameterTypes, arguments);
            }
        };
    }

    然后进入Wrapper#getWrapper--> Wrapper#makeWrapper, 具体代码就在这个makeWrapper方法里面

    例如现在暴露的服务如下:

    public interface TestService {
    
        String getData(String var1);
    
        List<String> getList();
    }

    那么生成的代理类如下:

    public class Wrapper0 extends com.alibaba.dubbo.common.bytecode.Wrapper {
    
        /**
         * 属性名, 属性类型
         */
        public static java.util.Map pts = new HashMap<String, Class<?>>();
        public static String[] pns = new String[0];
    
        /**
         * 所有的方法名
         */
        public static String[] mns = {"getData"};
        /**
         * 本类中的所有方法名
         */
        public static String[] dmns = {"getData"};
    
        /**
         * 一个方法中所有的参数类型  mts[n]属性的个数和方法的个数形同
         */
        public static Class[] mts0 = {String.class};
    
        public static Class[] mts1 = {List.class};
    
        @Override
        public String[] getPropertyNames() {
            return pns;
        }
    
        @Override
        public boolean hasProperty(String n) {
            return pts.containsKey(n);
        }
    
        @Override
        public Class getPropertyType(String n) {
            return (Class) pts.get(n);
        }
    
        @Override
        public String[] getMethodNames() {
            return mns;
        }
    
        @Override
        public String[] getDeclaredMethodNames() {
            return dmns;
        }
    
        @Override
        public void setPropertyValue(Object o, String n, Object v) {
            per.qiao.service.TestService w;
            try {
                w = ((per.qiao.service.TestService) o);
            } catch (Throwable e) {
                throw new IllegalArgumentException(e);
            }
            throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService.");
        }
    
        @Override
        public Object getPropertyValue(Object o, String n) {
            per.qiao.service.TestService w;
            try {
                w = ((per.qiao.service.TestService) o);
            } catch (Throwable e) {
                throw new IllegalArgumentException(e);
            }
            if (n.equals("list")) {
                return w.getList();
            }
            throw new com.alibaba.dubbo.common.bytecode.NoSuchPropertyException("Not found property \"" + n + "\" filed or setter method in class per.qiao.service.TestService.");
        }
        
        /**
         *  在调用接口时,就时调用的这个方法
            @param o 接口实例
            @param n 方法名
            @param p 参数类型
            @param v 参数
         */
        @Override
        public Object invokeMethod(Object o, String n, Class[] p, Object[] v) throws java.lang.reflect.InvocationTargetException {
            per.qiao.service.TestService w;
            try {
                w = ((per.qiao.service.TestService) o);
            } catch (Throwable e) {
                throw new IllegalArgumentException(e);
            }
            try {
                //这个try范围内就是你所需要暴露的所有方法
                if ("getData".equals(n) && p.length == 1) {
                    return w.getData((java.lang.String) v[0]);
                }
                if ("getList".equals(n) && p.length == 0) {
                    return w.getList();
                }
            } catch (Throwable e) {
                throw new java.lang.reflect.InvocationTargetException(e);
            }
            throw new com.alibaba.dubbo.common.bytecode.NoSuchMethodException("Not found method \"" + n + "\" in class per.qiao.service.TestService.");
        }
    }

    javassist生成动态代理类的示例

    public class CompilerByJavassist {
    
        public static void main(String[] args) throws Exception {
            // ClassPool:CtClass对象的容器
            ClassPool pool = ClassPool.getDefault();
    
            // 通过ClassPool生成一个public新类Emp.java
            CtClass ctClass = pool.makeClass("per.qiao.javassist.Qiao");
    
            // 添加属性 private String name
            CtField nameFild = new CtField(pool.getCtClass("java.lang.String"), "name", ctClass);
            nameFild.setModifiers(Modifier.PRIVATE);
            ctClass.addField(nameFild);
    
            // 其次添加熟悉privtae int age
            CtField ageField = new CtField(pool.getCtClass("int"), "age", ctClass);
            ageField.setModifiers(Modifier.PRIVATE);
            ctClass.addField(ageField);
    
            // 为属性name和age添加getXXX和setXXX方法
            ctClass.addMethod(CtNewMethod.getter("getName", nameFild));
            ctClass.addMethod(CtNewMethod.setter("setName", nameFild));
            ctClass.addMethod(CtNewMethod.getter("getAge", ageField));
            ctClass.addMethod(CtNewMethod.setter("setAge", ageField));
    
            // 添加构造函数
            CtConstructor ctConstructor = new CtConstructor(new CtClass[] {}, ctClass);
            // 为构造函数设置函数体
            StringBuffer buffer = new StringBuffer();
            buffer.append("{\n").append("name=\"qiaogege\";\n").append("age=25;\n}");
            ctConstructor.setBody(buffer.toString());
            // 把构造函数添加到新的类中
            ctClass.addConstructor(ctConstructor);
    
    
            // 添加自定义方法  public void printInfo {...}
            CtMethod ctMethod = new CtMethod(CtClass.voidType, "printInfo", new CtClass[] {}, ctClass);
            // 为自定义方法设置修饰符
            ctMethod.setModifiers(Modifier.PUBLIC);
            // 为自定义方法设置函数体
            StringBuffer buffer2 = new StringBuffer();
            buffer2.append("{\nSystem.out.println(\"begin!\");\n")
                    .append("System.out.println(name);\n")
                    .append("System.out.println(age);\n")
                    .append("System.out.println(\"over!\");\n").append("}");
            ctMethod.setBody(buffer2.toString());
            ctClass.addMethod(ctMethod);
    
    
            //最好生成一个class
            Class<?> clazz = ctClass.toClass();
            Object obj = clazz.newInstance();
            //ctClass.debugWriteFile("E://Qiao.class");
    
            //反射 执行方法
            obj.getClass().getMethod("printInfo", new Class[] {})
                    .invoke(obj, new Object[] {});
    
            ctClass.debugWriteFile("E://Emp.class");
            // 把生成的class文件写入文件
            byte[] byteArr = ctClass.toBytecode();
            FileOutputStream fos = new FileOutputStream(new File("E://Qiao.class"));
            fos.write(byteArr);
            fos.close();
        }
    
    }

    生成的Class文件放入IDEA中反编译后的结果如下

    public class Qiao {
        private String name = "qiaogege";
        private int age = 25;
    
        public String getName() {
            return this.name;
        }
    
        public void setName(String var1) {
            this.name = var1;
        }
    
        public int getAge() {
            return this.age;
        }
    
        public void setAge(int var1) {
            this.age = var1;
        }
    
        public Qiao() {
        }
    
        public void printInfo() {
            System.out.println("begin!");
            System.out.println(this.name);
            System.out.println(this.age);
            System.out.println("over!");
        }
    }

    小结:

    1. Dubbo通过javassist动态生成一个代理类对象,该对象不同于普通的javassist生成的对象,而是只记录了暴露接口中的方法的相关参数,生成一个Wrapper类型的对象,并保存在WRAPPER_MAP中,通过invokeMethod方法来执行相应的方法
    2. 再将生成的Wrapper对象包装在AbstractProxyInvoker中进行服务暴露

    转载于:https://www.cnblogs.com/qiaozhuangshi/p/11007024.html

    展开全文
  • Dubbo服务引用

    2019-12-04 07:56:41
    官网 客户端服务引用 客户端服务引用 demo DemoService demoService = (DemoService) context.getBean("demoService");...dubbo 在客户端动态生成了一个该 Interface 类型的代理类.在这个代理类中...

    官网

    客户端服务引用

    客户端服务引用 demo

    DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy
    demoService.sayHello("world");
    

    dubbo 在客户端动态的生成了一个该 Interface 类型的代理类.在这个代理类中封装了远程服务调用的组件.

    DemoService 创建

    <dubbo:reference id="demoService" group="g1" check="true" interface="com.alibaba.dubbo.demo.DemoService"
                         client="netty4" timeout="10000" callbacks="1000" registry="zk01" filter="demo2">
    

    Spring 容器启动时,AbstractBeanFactory.isFactoryBean() 会判断 demoService 配置的 RootBeanDefinition 的 beanType 为com.alibaba.dubbo.config.spring.ReferenceBean,它是个 FactoryBean,Spring 容器会创建 ReferenceBean 这个 FactoryBean 实例.

    获取 DemoService

    DemoService demoService = (DemoService) context.getBean("demoService"); // get remote service proxy
    

    会调用 factoryBean.getObject() 方法,即调用 ReferenceBean.getObject() 创建 demoService 实例.

    DUBBO-issue-2757 debug 时候遇到这个 bug 了,需要在 idea 里设置下.

    在服务提供方,Invoker 用于调用服务提供类.在服务消费方,Invoker 用于执行远程调用.

    客户端服务引用流程

    - refer
    - context.getBean("demoService")
        - ReferenceBean.getObject():通过这个 FactoryBean 创建 demoService 实例
            - ReferenceConfig.init(): 调用父类ReferenceConfig.init()
                - ReferenceConfig.createProxy(map)创建DemoService代理对象
                - 1.远程引用的逻辑
                - 1.1.loadRegistries()加载注册中心URL数组
                - 1.2.引用服务invoker = refprotocol.refer(interfaceClass, urls.get(0))
                    - Protocol$Adaptive.refer()
                        - ProtocolFilterWrapper.refer()
                            - ProtocolListenerWrapper.refer()
                                - RegistryProtocol.refer()
                                - 1.获取注册中心的url
                                - 2.获得注册中心registryFactory.getRegistry(url)
                                - 3.执行服务引用doRefer(cluster, registry, type, url)
                                    - RegistryProtocol.doRefer()
                                    - 1.根据DemoService的type和url创建RegistryDirectory 对象,并设置注册中心
                                    - 2.向注册中心注册自己(服务消费者)registry.register()
                                    - 3.向注册中心订阅 服务提供者 + 路由规则 + 配置规则
                                    - 4.通过cluster创建Invoker对象cluster.join(directory)并返回Invoker
                - 1.3.生成invoker的代理对象并返回 return (T) proxyFactory.getProxy(invoker)
                    - ProxyFactory$Adaptive().getProxy()
                        - JavassistProxyFactory.getProxy(invoker, interfaces)
                            - Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker))
                                - new InvokerInvocationHandler(invoker) // invoker为MockClusterInvoker实例
    

    客户端服务调用

    demoService.sayHello(“world”)

    - consumer-call
    - demoService.sayHello("world")
        - com.alibaba.dubbo.common.bytecode.proxy0.sayHello(name) // 服务代理类
            - InvokerInvocationHandler.invoke(proxy, method, args)
            - 1.获取参数名和方法名
            - 2.RPC调用invoker.invoke(new RpcInvocation(method, args)).recreate()
                - 1.将method和参数封装成RpcInvocation对象
                - 2.MockClusterInvoker.invoke(invocation)
                    - result = this.invoker.invoke(invocation)调用FailoverClusterInvoker.invoke(),先走父类AbstractClusterInvoker.invoke()
                        - 1.通过 directory 获得所有服务提供者 Invoker 集合RegistryDirectory.list(Invocation invocation)
                            - AbstractClusterInvoker.list(invocation)
                                - 1.AbstractDirectory.list(invocation)
                                    - RegistryDirectory.doList(invocation)
                                    - 1.从localMethodInvokerMap中根据methodName获取所有匹配的invokers
                                - 2.根据routers,调用router.route()筛选invokers
                                    - MockInvokersSelector.route()
                                        - 对于普通invoker集合,调用MockInvokersSelector.getNormalInvokers(invokers)
                                            - 不包含 MockInvoker 的情况下,直接返回 `invokers` 集合
                                - 3.获取loadBalance,默认是RandomLoadBalance实例
                                - 4.doInvoke(invocation, invokers, loadbalance)执行调用
                                    - FailoverClusterInvoker.doInvoke()中
                                    - 1.获取最大可调用次数: 最大可重试次数 + 1
                                    - 2.select(loadbalance, invocation, copyinvokers, invoked)根据负载均衡机制从 copyinvokers 中选择一个Invoker
                                        - AbstractClusterInvoker.doselect()
                                        - 1.若只有一个invoker直接选择
                                        - 2.如果只有两个Invoker,轮循取
                                        - 3.其余loadbalance.select(invokers, getUrl(), invocation)使用loadbalance获取invoker对象
                                            - // doSelect()具体的loadbalance算法实现
                                    - 3.将选中的invoker添加到invoked(保存已经调用过的invokers)中,并设置到context里
                                    - 4.发起RPC调用并返回result,invoker.invoke(invocation)
                                        - invokerWrapper.invoke(invocation)
                                            - ProtocolFilterWrapper$1.invoke()后面会调用filter链
                                - 5.调用成功就直接返回result了,失败则根据重试次数和策略重新选中invoker调用
    
    展开全文
  • dubbo服务运行过程中,上传正确的java代码文件,自动编译生成class并注册到dubbo zk 中,可以正常dubbo invoke来调用。整个过程服务不用重启。我写了个框架并命名为D-Unit。 2.框架用法 1.项目配置xml文件,配置...
  • 接上篇《Dubbo技术知识总结之五——Dubbo远程调用》 六. Dubbo 服务调用链路 参考地址:《Dubbo服务消费者和服务提供者之间的请求和响应过程》 ...它是一个通过动态代理方式生成的代理对象,可以通过 Netty Cli.
  • dubbo服务相关面试题

    2020-12-16 10:58:14
    请介绍⼀下Dubbo服务消费者调用服务提供者的过程? 1.整体流程图 通过上面的流程图可以知道,服务消费者通过代理对象Proxy发起远程调用,接着通过网络客户端Client将编码后的请求发送给服务提供方的网络层上,也...
  • 前面一篇讲了服务调用方启动的大致流程 本章主要讲refer服务引用,分成两个重点,一个是创建invoker,一个是创建代理。
  • 前面消费者提到过代理对象是通过JavassistProxyFactory 动态生成的,所以当调用sayHelloService.sayHello(name); 时,实际上是调用proxy里面的返回的 InvokerInvocationHandler包装过的,基于前面已经包装过的...
  • Apache Dubbo服务通信及负载均衡 客户端生成的proxy 上次,我们分析到消费者初始化完成之后,会生成一个proxy,而这个proxy本质上是一个动态代理类。 JavassistProxyFactory.getProxy @Override @SuppressWarnings(&...
  • Dubbo

    2020-09-18 19:25:53
    说明:只要使用Dubbo框架 ,在内部使用了dubbo协议进行通讯,其中的IP地址是动态生成的.并且端口号是访问服务的唯一标识信息. 2 ZK存储数据的结构 说明:zk中的数据的存储的方式是树形结构的.一般三级. 3 关于负载均衡...
  • 整体RPC的消费原理: ReferenceCnofig ↓ Protocol ----> Dubbo、injvm等 ↓ Invoker -----> DubboInvoker等 ↓ ProxyFactoy ----->...第一部分通过持有远程服务实例生成In
  • 微服务dubbo面试题

    2019-06-13 14:48:00
    dubbo的工作原理? dubbo支持的序列化协议? ...动态代理策略?...dubbo服务接口的幂等性如何设计(比如不能重复扣款,不能重复生成订单,不能重复创建卡号? dubbo服务接口请求的顺序性如何保证?...
  • dubbo 源码

    2020-09-28 11:04:19
    推荐使用xml ,api当在和别的框架集合时使用 还有注解方式 ...如果需要饥饿加载,即没有人引用也立即生成动态代理,可以配置:<dubbo:reference … init=“true” /> 注解 @Configuration @EnableDubbo
  • (1)dubbo工作原理:服务注册,注册中心,消费者,代理通信,负载均衡 (2)网络通信、序列化:dubbo协议,长连接,NIO...怎么生成动态代理? (4)dubbo SPI机制:你了解不了解dubbo的SPI机制?如何基于SPI机制...
  • @Dubbo与@Transactional冲突,导致服务无法发布问题分析解决方法 问题分析 spring在处理@Transactional注释的类时,会有jdk动态代理和cglib动态代理两种方式生成代理类。jdk动态代理生成的代理类会实现与被代理类...
  • Dubbo框架使用踩坑记

    2020-04-28 13:17:37
    dubbo服务调者项目启动时报错:java.lang.NoClassDefFoundError:could not initialize class ...是因为缺少javassist.jar导致,因为dubbo需要动态生成字节码。 加上javassist.jar后启动又报错:java.lang.NoC...
  • 2.服务目录在获取注册中心的服务配置信息后,会为每条配置信息生成一个 Invoker 对象,并把这个 Invoker 对象存储起来,这个 Invoker 才是服务目录最终持有的对象。 3.Invoker这是一个具有远程调用功能的对象。 4....
  • 1.获取动态代理对象 (1)通过工厂创建bean(2) 生成代理对象 2.获取invoker 总结: 在调用代理对象的方法的时候触发代理对象初始化,真正的创建代理对象 判断是否是本地调用((1)若dubbo:reference/的url属性不...
  • 开源的Dubbo服务管理控制台是阿里巴巴内部裁剪版本,开源部分主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。 二、管理控制台的搭建 2.1 打包生成管理控制台war包 ...
  • Dubbo的Javassist代理

    2019-08-08 13:40:55
    Javassist 生成动态代理可以使用两种方式,一种使用代理工厂创建,和普通的...而Dubbo中默认采用javassit代理,动态的在内存当中生成所代理类的字节码,来完成代理的功能。 可以看到,javassit的代理工厂类只实...
  • Javassist代理 Dubbo源码

    2018-05-30 13:31:27
    Dubbo中默认采用javassit代理在内存中动态生成所代理的字节码。我们来看下JavassistProxyFactory中的代码 public &lt;T&gt; T getProxy(Invoker&lt;T&gt; invoker, Class&lt;?&gt;[] ...
  • Dubbo的主要作用?

    2020-02-13 08:48:38
    透明化的远程方法调用,像调用本地方法一样调用远程方法 负载均衡及容错机制,负载分发请求到不同的服务提供者,解决单点故障 服务自动注册与发现,动态服务注册与请求分发,能够... 文件解析与生成 Linux MyS...
  • Dubbo 的内核解析 ...Dubbo 通过这四种机制实现了对插件的 IoC、AOP,实现了对自动生成类的动态编译 Compile。 1. JDK 的 SPI 机制 1.1 简介 SPI,Service Provider Interface,服务提供者接口,是一种
  • dubbo调用过程

    2020-05-08 15:24:06
    完成了服务的初始化之后,生成了代理,生成动态代理类对接口的方法进行了包装,每次调用都会调用到InvocationHandler的invoke()方法,此方法中会进行远程服务调用一些列复杂过程,诸如网络通信,编码,解码,序列...
  • Dubbo 代码结构整理

    2018-04-13 01:32:31
    先上张图,可以看到dubbo的模块划分和层次划分有一定对应关系,我的水平评价不出代码好坏,但是很喜欢这种代码结构。... Proxy:使用javassist、或者jdk动态代理生成的类,以及stub和local功能的实现。服务端的Abst...
  • Dubbo通信底层分析

    2018-06-04 11:27:15
    它的底层是采用Socket通信和动态代理实现的,首先服务端启动时,会在注册中心上发布服务,其实就是接口的描述信息,客户端启动时,根据需要从注册中心订阅自己所需要的服务,也就是接口描述信息,生成一个代理类,...
  • dubbo SPI机制

    2017-01-06 16:10:22
    为实现在模块装配的时候不在程序里动态指明,这就需要一种服务发现机制。   原理 java spi和所有实现接口的厂商有一个俗称的约定,只要将META-INF/services文件夹下生成一个和抽象类全名称相同的配置文件,那么...
  • dubbo负载均衡策略和集群容错策略都有哪些? 1)dubbo工作原理:服务...怎么生成动态代理? (4)dubbo SPI机制:你了解不了解dubbo的SPI机制?如何基于SPI机制对dubbo进行扩展? Dubbo负载均衡策略 random loadBalan

空空如也

空空如也

1 2 3 4
收藏数 80
精华内容 32
关键字:

动态生成dubbo服务