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方法,最终完成服务引用。
其实服务引用做的事情,就是根据配置生成服务方在消费方的代理类,以供消费方调用。本文只是讲述了服务引用的触发时机,服务引用的详细流程,以后待续。
浙公网安备 33010602011771号