Dubbo源码学习之-谈谈服务引用的触发时机

前言

    Dubbo中服务引用部分涉及到的内容较多,且属于承前启后的地位,涉及到的是Dubbo的核心功能。原本草稿已经准备的差不多了,但今天随手翻了一下网上其他人对Dubbo服务引用的讲解,发现我准备的跟他们已经做好的没什么差别,不仅毫无新意,而且还有很多不足,所以就先不献丑,等后面有新颖想法的时候再整理这部分。本文只介绍Dubbo触发服务引用的时机,即在Spring容器启动的什么时候触发。

正文

    服务引用操作的对象是ReferenceBean。当在解析Dubbo配置文件时,会在DubboNamespaceHandler中完成解析的绑定,该类代码如下所示:

 1 public class DubboNamespaceHandler extends NamespaceHandlerSupport {
 2 
 3     static {
 4         Version.checkDuplicate(DubboNamespaceHandler.class);
 5     }
 6 
 7     @Override
 8     public void init() {
 9         registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
10         registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
11         registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
12         registerBeanDefinitionParser("config-center", new DubboBeanDefinitionParser(ConfigCenterBean.class, true));
13         registerBeanDefinitionParser("metadata-report", new DubboBeanDefinitionParser(MetadataReportConfig.class, true));
14         registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
15         registerBeanDefinitionParser("metrics", new DubboBeanDefinitionParser(MetricsConfig.class, true));
16         registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
17         registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
18         registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
19         registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
20         registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false)); // 此处完成reference标签的解析配置,放入spring中管理
21         registerBeanDefinitionParser("annotation", new AnnotationBeanDefinitionParser());
22     }
23 
24 }

DubboNamespaceHandler是在META-INF下的spring.handlers文件中默认配置的,具体可参见之前的spring自定义标签解析一文。

官方文档中对服务引用有说明,有两种情况会触发服务引用:一种是ReferenceBean初始化的时候;另一种是ReferenceBean对应的服务被注入到其他类中时引用。下面我们就针对这两种情况展开详细分析。

我们先看一下ReferenceBean的代码结构(只列出了主要的几个方法):

 1 public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
 2 
 3     private transient ApplicationContext applicationContext;
 4 
 5     @Override
 6     public void setApplicationContext(ApplicationContext applicationContext) {
 7         this.applicationContext = applicationContext;
 8         SpringExtensionFactory.addApplicationContext(applicationContext);
 9     }
10 
11     @Override
12     public Object getObject() {
13         return get();
14     }
15 
16 
17     @Override
18     @SuppressWarnings({"unchecked"})
19     public void afterPropertiesSet() throws Exception {
20     // 省略N行代码    
21 if (shouldInit()) {getObject();}
21     }
22 }

    可以看到,它实现了FactoryBean和InitializingBean接口。对服务引用的触发,就是这两个接口控制的。

    对FactoryBean熟悉的园友应该知道,如果spring中的一个bean实现了FactoryBean,那么在你调用getBean方法或者对该bean进行依赖注入的时候,最终获取到的是getObject方法的返回值,此处也是同样道理。我们可以看到,在getObject方法中调用了get()方法,该方法是父类ReferenceConfig中的方法,触发了服务引用。这就是【ReferenceBean对应的服务被注入到其他类中时触发引用】。

    而对于InitializingBean接口,其重写方法是afterPropertiesSet,该方法是在哪里调用的?是在完成bean的实例化之后,AbstractAutowireCapableBeanFactory的initializeBean中调用的。在initializeBean方法中,先调用BeanPostProcessor的postProcessBeforeInitialization方法,然后调用了此处的主角afterPropertiesSet方法,最终完成服务引用。

    其实服务引用做的事情,就是根据配置生成服务方在消费方的代理类,以供消费方调用。本文只是讲述了服务引用的触发时机,服务引用的详细流程,以后待续。

 

posted on 2019-09-07 22:50  淡墨痕  阅读(410)  评论(0)    收藏  举报