• 第三章 dubbo内核之ioc源码解析


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

    1 createAdaptiveExtension()
    2 --injectExtension((T) getAdaptiveExtensionClass().newInstance()) //为创建好的AdaptiveExtensionClass实例进行属性注入
    3 
    4 createExtension(String name)
    5 --injectExtension(instance) //为创建好的Extension实例进行属性注入
    6 --injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)) //为创建好的wrapperClass实例进行属性注入

    来看一下源码:

     1     /**
     2      * dubbo-IOC的核心
     3      */
     4     private T injectExtension(T instance) {
     5         try {
     6             if (objectFactory != null) {
     7                 for (Method method : instance.getClass().getMethods()) {
     8                     if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
     9                         && Modifier.isPublic(method.getModifiers())) {//一个参数的public的setXXX(T param)方法.例如,setName(String name)
    10                         Class<?> pt = method.getParameterTypes()[0];//参数param的类型T,eg.String
    11                         try {
    12                             String property = method.getName().length() > 3
    13                                 ? method.getName().substring(3, 4).toLowerCase() + method.getName().substring(4) : "";//获取属性名XXX, eg.name
    14                             Object object = objectFactory.getExtension(pt, property);//实例化参数
    15                             if (object != null) {
    16                                 //执行instance.method(object)方法,这里就是执行instance的setter方法,进行setter注入
    17                                 method.invoke(instance, object);
    18                             }
    19                         } catch (Exception e) {
    20                             logger.error("fail to inject via method " + method.getName() + " of interface "
    21                                          + type.getName() + ": " + e.getMessage(),
    22                                 e);
    23                         }
    24                     }
    25                 }
    26             }
    27         } catch (Exception e) {
    28             logger.error(e.getMessage(), e);
    29         }
    30         return instance;
    31     }

    整个方法的作用就是通过instance对象实例的setter方法为instance的属性赋值,完成setter注入,即IOC的最经典的注入方式。

    详细步骤:

    • 获取instance的setter方法,通过setter方法获取属性名称property和属性类型pt(即paramType的简写)
    • 使用objectFactory创建一个property名称(类型为pt)的对象实例
    • 执行instance的setter方法,注入property实例

    其中,比较重要的就是:Object object = objectFactory.getExtension(pt, property);这个方法。其中的objectFactory=AdaptiveExtensionFactory实例,其属性factories = [SpringExtensionFactory实例, SpiExtensionFactory实例]。

    看一下源码:

     1     private final List<ExtensionFactory> factories;
     2 
     3     public <T> T getExtension(Class<T> type, String name) {
     4         /**
     5          * 先调用SpiExtensionFactory来实例化;
     6          * 如果不行,再使用SpringExtensionFactory来实例化
     7          */
     8         for (ExtensionFactory factory : factories) {
     9             T extension = factory.getExtension(type, name);
    10             if (extension != null) {
    11                 return extension;
    12             }
    13         }
    14         return null;
    15     }

    看一下SpiExtensionFactory的源码:

     1 public class SpiExtensionFactory implements ExtensionFactory {
     2     public <T> T getExtension(Class<T> type, String name) {
     3         if (type.isInterface() && type.isAnnotationPresent(SPI.class)) {//type是接口且必须具有@SPI注解
     4             ExtensionLoader<T> loader = ExtensionLoader.getExtensionLoader(type);
     5             if (loader.getSupportedExtensions().size() > 0) {//获取type的所有ExtensionClasses实现的key
     6                 return loader.getAdaptiveExtension();//获取type的装饰类,如果有@Adaptive注解的类,则返回该类的实例,否则返回一个动态代理类的实例(例如Protocol$Adpative的实例)
     7             }
     8         }
     9         return null;
    10     }
    11 }

    从这里我们可以看出dubbo-SPI的另外一个好处:可以为SPI实现类注入SPI的装饰类或动态代理类。

    看一下SpringExtensionFactory的源码:

     1 public class SpringExtensionFactory implements ExtensionFactory {
     2     private static final Set<ApplicationContext> contexts = new ConcurrentHashSet<ApplicationContext>();
     3     
     4     public static void addApplicationContext(ApplicationContext context) {
     5         contexts.add(context);
     6     }
     7 
     8     public static void removeApplicationContext(ApplicationContext context) {
     9         contexts.remove(context);
    10     }
    11 
    12     @SuppressWarnings("unchecked")
    13     public <T> T getExtension(Class<T> type, String name) {
    14         for (ApplicationContext context : contexts) {
    15             if (context.containsBean(name)) {//该context是否包含name的bean
    16                 Object bean = context.getBean(name);//获取name的bean,如果是懒加载或多例的bean,此时会实例化name的bean
    17                 if (type.isInstance(bean)) {//如果obj的类型是type或其子类,与instanceof相同
    18                     return (T) bean;
    19                 }
    20             }
    21         }
    22         return null;
    23     }
    24 }

    至此,IOC就干完了。但是有一个遗留问题,ApplicationContext是什么时候加入到contexts中呢?当讲解ServiceBean的时候来说。

  • 相关阅读:
    单工、半双工和双工通信
    Callable和Future
    有状态和无状态服务
    paxos协议
    OOP面向对象编程的三大特性
    php工厂模式
    php 观察者模式
    php的单例模式
    php是单继承还是多继承呢?
    MySQL—内连接join 和外连接 left join 区别 交叉连接 a,b cross joni union 联合
  • 原文地址:https://www.cnblogs.com/java-zhao/p/7469786.html
Copyright © 2020-2023  润新知