• 04_dubbo_ioc


    【dubbo的IOC实现方法】

    dubbo的IOC具体实现在:T injectExtension( T instance )方法中,该方法在3个地方被使用:

    ExtensionLoader.getExtensionLoader(Protocol.class)
    --new ExtensionLoader<T>(type)
    ----getAdaptiveExtension()
    ------createAdaptiveExtension()
    /**1.为创建好的AdaptiveExtensionClass实例进行属性注入**/
    --------injectExtension((T) getAdaptiveExtensionClass().newInstance())  
    
    /**2.为创建好的Extension实例进行属性注入**/
    ExtensionLoader.getExtension("dubbo")
    --createExtension("dubbo")
    ----injectExtension(instance);
    /**3.为创建好的wrapperClass实例进行属性注入**/
    ----injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) //

    injectExtension( T instance )源码】

    injectExtension( T instance )方法的作用是通过instance对象的实例的setXxx(object)方法为instance的属性进行赋值,完成setter注入,类似Spring的ioc的经典注入方式。

    详细步骤:

    1.获取instance的setXxx方法,通过setXxx方法获取属性名称property和属性类型pt。

    2.使用objectFactory创建属性property的对象实例object

    3.执行method.invoke( instance, object ),注入property实例,即执行setXxx(object)方法

    private T injectExtension(T instance) {
        try {
            if (objectFactory != null) {
                for (Method method : instance.getClass().getMethods()) {
                    //成员变量的setXxx(T param)方法,例如:setName(String name)
                    if (method.getName().startsWith("set")
                            && method.getParameterTypes().length == 1
                            && Modifier.isPublic(method.getModifiers())) {
                        //获取参数param的类型的Class对象
                        Class<?> pt = method.getParameterTypes()[0];
                        try {
                            //通过方法名setXxx获取成员变量名xxx,例如setName-->name
                            String property = method.getName().length() > 3 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";
                            //实例化参数object
                            Object object = objectFactory.getExtension(pt, property);
                            if (object != null) {
                                //执行instance实例对应的setXxx(object)方法,参数是object
                                method.invoke(instance, object);
                            }
                        } catch (Exception e) {
                            logger.error("fail to inject via method " + method.getName()
                                    + " of interface " + type.getName() + ": " + e.getMessage(), e);
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return instance;
    }

     其中,比较重要的是

    Object object = objectFactory.getExtension(pt, property);

    这个方法,其中的ExtensionFactory objectFactory实例为 AdaptiveExtensionFactory实例,即

    //伪代码
    ExtensionFactory objectFactory = AdaptiveExtensionFactory实例

    AdaptiveExtensionFactory的成员变量

    factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]

    【 AdaptiveExtensionFactory 类源代码】

    /**
     * AdaptiveExtensionFactory
     *
     * @author william.liangf
     */
    @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);
        }
    
       /**
        * 先调用SpiExtensionFactory来实例化
        * 如果不行,再使用SpringExtensionFactory来实例化
        **/
        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;
        }
    
    }

    【SpiExtensionFactory源码】

    /**
     * SpiExtensionFactory
     *
     * @author william.liangf
     */
    public class SpiExtensionFactory implements ExtensionFactory {
    
        public <T> T getExtension(Class<T> type, String name) {
            //type是接口类型,且必须含有@SPI注解
            if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {
                ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
                //获取type的所有ExtensionClasses实现的key(例如:type是Protocol.class)
                if (loader.getSupportedExtensions().size() > 0) {
                    //获取type的装饰类,如果有@Adaptive注解的类,则返回该类的实例,否则返回一个动态代理的实例(如:Protocol$Adaptive 的实例)
                    return loader.getAdaptiveExtension();
                }
            }
            return null;
        }
    
    }

     结论:dubbo-spi相对于JDK-spi的一个好处,可以为SPI实现类注入SPI的装饰类或动态代理类。

    【 SpringExtendsionFactory的源码 】

    /**
     * SpringExtensionFactory
     *
     * @author william.liangf
     */
    public class SpringExtensionFactory implements ExtensionFactory {
    
        private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
    
        public static void addApplicationContext(ApplicationContext context) {
            contexts.add(context);
        }
    
        public static void removeApplicationContext(ApplicationContext context) {
            contexts.remove(context);
        }
    
        @SuppressWarnings("unchecked")
        public <T> T getExtension(Class<T> type, String name) {
            for (ApplicationContext context : contexts) {
                //该context是否包含name的bean
                if (context.containsBean(name)) {
                    //获取该name对应的bean,如果是懒加载或者多实例的bean,此时会实例化name对应的bean
                    Object bean = context.getBean(name);
                    //如果obj的类型是typ或者其子类,与instance相同
                    if (type.isInstance(bean)) {
                        return (T) bean;
                    }
                }
            }
            return null;
        }
    
    }

     【参考文章】

    https://www.cnblogs.com/java-zhao/p/7469786.html

  • 相关阅读:
    从数据到代码—通过代码生成机制实现强类型编程
    .NET中oledb访问access含子查询的语句的参数置换顺序
    Android开发入门学习
    Shell脚本初步学习鸟哥Linux私房菜基础学习篇
    rpm打包学习
    关于计算机工作方向的几点想法
    source insight中文注释乱码问题的解决方案
    makefilerpm编译软件,输出依赖软件包的编译顺序
    在android中资源文件夹中添加一个新的图片资源
    Linux批量替换某种类型文件中的字符串sed和grep命令使用
  • 原文地址:https://www.cnblogs.com/HigginCui/p/9610021.html
Copyright © 2020-2023  润新知