zoukankan      html  css  js  c++  java
  • dubbo 代理和自动注入原理

    示例接口如下:

    @SPI
    public interface BallInterface {
        @Adaptive("ball")
        String getBall(URL url);
    }

    dubbo的代理有两种情况:

    (1)基于构造函数的静态代理(通过简单的包装对象进行操作)

    public class ConstructBallInterface implements BallInterface {
        private BallInterface ballInterface;
    
        //通过构造函数进行代理
        public ConstructBallInterface(BallInterface ballInterface) {
            this.ballInterface = ballInterface;
        }
    
        @Override
        public String getBall(URL url) {
            System.out.println("start");
            String bbb = ballInterface.getBall(url);
            System.out.println("end");
            return bbb;
        }
    }

    (2)动态代理有两种方式:

    (2-1)通过@Adaptive注解的动态代理

    @Adaptive//这个注解很关键,如果有了这个注解并实现接口,就不会动态生成代理类型load进行来
    public class AnnotationBallInterface implements BallInterface {
    
        @Override
        public String getBall(URL url) {
            System.out.println("start");
            return "1";
        }
    }

    (2-2)通过AdaptiveClassCodeGenerator的字节码生成动态代理

    在生成动态代理类的过程中,我们看下dubbo的自动注入机制,dubbo的自动注入机制是通过两个关键点:

    1.判断是否有set方法

    2.判断set方法参数是否为标记了@SPI注解

    获取接口实现类:

      ExtensionLoader<BallInterface> service = ExtensionLoader.getExtensionLoader(BallInterface.class);
      URL url = new URL("", "", 12, new HashMap<String, String>() {{
    put("ball", "ui");
    }});
     BallInterface red = service.getExtension("red");

    调用injectExtension方法,在这里通过AdaptiveExtensionFactory类的getExtension获取扩展,这里使用了我们上文提到了的基于注解的代理方式。

    @Adaptive
    public class AdaptiveExtensionFactory implements ExtensionFactory {
    
        private final List<ExtensionFactory> factories;
    
        public AdaptiveExtensionFactory() {
            ExtensionLoader<ExtensionFactory> loader = ExtensionLoader.getExtensionLoader(ExtensionFactory.class);
            List<ExtensionFactory> list = new ArrayList<ExtensionFactory>();
            for (String name : loader.getSupportedExtensions()) {
                list.add(loader.getExtension(name));
            }
            factories = Collections.unmodifiableList(list);
        }
    
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            for (ExtensionFactory factory : factories) {
                T extension = factory.getExtension(type, name);
                if (extension != null) {
                    return extension;
                }
            }
            return null;
        }
    
    }

    在这里间接获取的ExtensionFactory的SPI实现类是SpiExtensionFactory,而getAdaptiveExtension方法中就是获取动态代理对象

    public class SpiExtensionFactory implements ExtensionFactory {
    
        @Override
        public <T> T getExtension(Class<T> type, String name) {
            if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
                ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
                if (!loader.getSupportedExtensions().isEmpty()) {
                    return loader.getAdaptiveExtension();
                }
            }
            return null;
        }
    }

     上面的方法中实际创建了动态代码对象后调用generate方法生成类:new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();,generate方法实现如下:

    public String generate() {
            // no need to generate adaptive class since there's no adaptive method found.
            if (!hasAdaptiveMethod()) {
                throw new IllegalStateException("No adaptive method exist on extension " + type.getName() + ", refuse to create the adaptive class!");
            }
    
            StringBuilder code = new StringBuilder();
            code.append(generatePackageInfo());
            code.append(generateImports());
            code.append(generateClassDeclaration());
    
            Method[] methods = type.getMethods();
            for (Method method : methods) {
                code.append(generateMethod(method));
            }
            code.append("}");
    
            if (logger.isDebugEnabled()) {
                logger.debug(code.toString());
            }
            return code.toString();
        }

    生成的类内容如下,动态代理对象需要依赖外部的URL参数,来完成对持有对象的控制,URL是dubbo中的数据传递总线:

    package test;
    
    import org.apache.dubbo.common.extension.ExtensionLoader;
    
    public class BallInterface$Adaptive implements test.BallInterface {
        public java.lang.String getBall(org.apache.dubbo.common.URL arg0) {
            if (arg0 == null) throw new IllegalArgumentException("url == null");
            org.apache.dubbo.common.URL url = arg0;
            String extName = url.getParameter("ball");//动态代理对象需要依赖外部的URL参数,来完成对持有对象的控制
            if (extName == null)
                throw new IllegalStateException("Failed to get extension (test.BallInterface) name from url (" + url.toString() + ") use keys([ball])");
            test.BallInterface extension = (test.BallInterface) ExtensionLoader.getExtensionLoader(test.BallInterface.class).getExtension(extName);
            return extension.getBall(arg0);
        }
    }

     我们回到injectExtension方法中,反射set方法将代理对象传入方法中:

      private T injectExtension(T instance) {
    
            if (objectFactory == null) {
                return instance;
            }
    
            try {
                for (Method method : instance.getClass().getMethods()) {
                    if (!isSetter(method)) {
                        continue;
                    }
                    /**
                     * Check {@link DisableInject} to see if we need auto injection for this property
                     */
                    if (method.getAnnotation(DisableInject.class) != null) {
                        continue;
                    }
                    Class<?> pt = method.getParameterTypes()[0];
                    if (ReflectUtils.isPrimitives(pt)) {
                        continue;
                    }
    
                    try {
                        String property = getSetterProperty(method);
                        Object object = objectFactory.getExtension(pt, property);
                        if (object != null) {
                            method.invoke(instance, object);//反射调用set方法进行注入
                        }
                    } catch (Exception e) {
                        logger.error("Failed to inject via method " + method.getName()
                                + " of interface " + type.getName() + ": " + e.getMessage(), e);
                    }
    
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
            return instance;
        }
  • 相关阅读:
    Mysql基础学习
    shell中脚本调试----学习
    Eureka 集群Demo
    Java获取到异常信息进行保存(非Copy)
    Feign String 参数 传递null 以及 空字符串问题
    Eureka系列(九)Eureka自我保护机制
    Eureka系列(八)服务剔除具体实现
    Eureka系列(六) TimedSupervisorTask类解析
    Eureka系列(五) 服务续约流程具体实现
    Eureka系列(四) 获取服务Server端具体实现
  • 原文地址:https://www.cnblogs.com/zzq-include/p/12258574.html
Copyright © 2011-2022 走看看