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;
        }
  • 相关阅读:
    模拟赛总结
    2018.04.06学习总结
    2018.04.06学习总结
    Java实现 LeetCode 672 灯泡开关 Ⅱ(数学思路问题)
    Java实现 LeetCode 671 二叉树中第二小的节点(遍历树)
    Java实现 LeetCode 671 二叉树中第二小的节点(遍历树)
    Java实现 LeetCode 671 二叉树中第二小的节点(遍历树)
    Java实现 LeetCode 670 最大交换(暴力)
    Java实现 LeetCode 670 最大交换(暴力)
    Java实现 LeetCode 670 最大交换(暴力)
  • 原文地址:https://www.cnblogs.com/zzq-include/p/12258574.html
Copyright © 2011-2022 走看看