dubbo内核之ioc源码解析

未来已来2018-11-25 11:00

此文已由作者赵计刚薪授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


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的时候来说。


免费体验云安全(易盾)内容安全、验证码等服务

更多网易技术、产品、运营经验分享请点击