dubbo源码解析

1.先了解下dubbo的常用配置

<dubbo:service/> 服务配置,用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心。

例子<dubbo:service ref="helloServiceDubbo" interface="com.dubbozone.service.dubbo.HelloServiceDubbo" version="1.0.0" protocol="http" path="api/hello" timeout="60000" />

<dubbo:reference/> 引用服务配置,用于创建一个远程服务代理,一个引用可以指向多个注册中心。

例子<dubbo:reference ref="helloServiceDubbo" interface="com.dubbozone.service.dubbo.HelloServiceDubbo" />

<dubbo:protocol/> 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。

例子<dubbo:protocol host="${dubboHost}" name="http" port="${dubboPort}" server="servlet" contextpath="${dubboContextpath}" />

<dubbo:application/> 应用配置,用于配置当前应用信息,不管该应用是提供者还是消费者。

例子<dubbo:application name="member"/> 

<dubbo:module/> 模块配置,用于配置当前模块信息,可选。

<dubbo:registry/> 注册中心配置,用于配置连接注册中心相关信息。

例子<dubbo:registry protocol="zookeeper" address="${zk.ip}" />

<dubbo:monitor/> 监控中心配置,用于配置连接监控中心相关信息,可选。

例子<dubbo:monitor protocol="registry" />

<dubbo:provider/> 提供方的缺省值,当ProtocolConfig和ServiceConfig某属性没有配置时,采用此缺省值,可选。

例子<dubbo:provider timeout="60000" retries="0" loadbalance="random" />

<dubbo:consumer/> 消费方缺省配置,当ReferenceConfig某属性没有配置时,采用此缺省值,可选。

例子<dubbo:consumer timeout="60000" check="false" />

 还有其他一些属性,可以去dubbo官网查看

http://dubbo.apache.org/books/dubbo-user-book/references/xml/introduction.html

2.了解下spring是怎么识别dubbo的

后面会结合官网提供的暴露服务时序图来对dubbo服务进行一个讲解,今天先讲一个spring是怎么实现跟dubbo结合的,dubbo是什么时候触发export方法然后暴露服务的。

dubbo源码解析

 

基于tomcat来分析dubbo的暴露服务

启动tomcat,在spring 容器启动时,会读取dubbo的配置文件,dubbo的配置如下

dubbo源码解析
各个配置的含义上面已经介绍。

在spring加载dubbo配置文件前,先简单了解下spring的bean初始化机制:Spring的InitializingBean接口有很好的用处,位于spring beans中,它只提供一个方法afterPropertiesSet(),当你实现了该方法后,spring就会对你提供框架级的支持:当你通过sring容器生产出实现了该接口的类的实例后,它就会调用afterPropertiesSet方法,通过这个方法,你可以检查你的bean是否正确地被初始化了.当然,你也可以用init-method方法.这两种方式可以同时使用,调用的顺序为init-method后调用。

 

Spring读取配置文件,关键是dubbo:service标签,每个dubbo:service标签都对应一个ServiceBean实例。

来看下ServiceBean.java.这个类的定义

public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener<ContextRefreshedEvent>, BeanNameAware {...}

这里有个关键地方:ApplicationContextAware和InitializingBean以及ApplicationListener(注意:下面三个步骤是在容器初始化的时候是按顺序来的)

1.实现了ApplicationContextAware类的setApplicationContext方法。把spring的上下文applicationContext赋给当前类中的变量,同时维护到dubbo中,通过反射调用AbstractApplicationContext.addApplicationListener方法,把当前servicebean对象作为listener添加到abstractapplicationContext中,并标记supportedApplicationListener为true。

 

2.ServiceBean实现了Spring提供的接口InitializingBean。当在完成Bean初始化和注入的时候程序会自动执行InitializingBean接口中的afterPropertiesSet方法(配置了几个dubbo:service,就会执行几次改方法,因为初始化与之匹配的servicebean)。在这个方法里面会对provider、application、module、registries、moniter、protocols、path等进行初始化。

如果没有设置延迟加载,则不会执行export()

if (! isDelay()) {

export();

}

也就是说并没有在此时进行服务暴漏。

 

3.实现了ApplicationListener接口的onApplicationEvent方法。ApplicationContext在运行期会自动检测到所有实现了ApplicationListener的bean对象,并将其作为事件接收对象,由此可知初始化的servicebean全部作为事件接收对象,当ApplicationContext的publishEvent方法被触发时,每个实现了ApplicationListener接口的bean都会收到ApplicationEvent对象,每个ApplicationListener可根据事件类型只接收处理自己感兴趣的事件,通过查看service源码,

public void onApplicationEvent(ContextRefreshedEvent event) {

        if (isDelay() && !isExported() && !isUnexported()) {

            if (logger.isInfoEnabled()) {

          logger.info("The service ready on spring started. service: " + getInterface());

            }

            export();

        }

 }

可知每个servicebean对ContextRefreshedEvent感兴趣,当有ContextRefreshedEvent事件发生时,会进行export(),export操作就是dubbo开始暴露服务的入口。

 

关于ContextRefreshedEvent是何时触发的,由谁触发的来介绍下:在Spring中,ApplicationContext的子类AbstractApplicationContext的refresh()是构建Bean的入口点,spring在加载bean的时候,就会执行ConfigurableApplicationContext的refresh方法,看下refresh方法的实现:

 
dubbo源码解析

finishRefresh的方法如下:


dubbo源码解析
由上可知,当spring加载完一个bean的时候就会publishContextRefreshedEvent事件,而dubbo的servicebean监听了该事件,所以当该类型事件发生时,sevicebean会触发onApplicationEvent(ContextRefreshedEvent event),然后就会调用export方法了,dubbo时序图中的第一步找到了。

 

相关推荐