概述
- Dubbo框架主要是用于分布式系统中服务之间的远程调用。而分布式系统中的每个服务一般为采用spring框架搭建,通过spring容器管理beans,通过spring mvc提供restful接口,在service层进行业务逻辑处理。而不管是服务消费者引用的bean,还是服务提供者需要对外提供服务、进行注册的bean,都需要一种机制来触发其进行初始化,生成JVM堆的一个对象实例,同时由spring容器管理,可以通过@Autowired进行注入,从而可以在运行时进行调用。
- 在dubbo源码结构中,主要在dubbo-config模块进行服务建模。具体为在dubbo-config-api子模块对服务进行各粒度的建模,依次为应用、提供者、消费者、注册中心、服务模块、服务提供类和引用类、方法、方法参数;在dubbo-config-spring子模块将消费者配置引用的服务,提供者配置对外提供调用的服务分别融合到相应项目的spring容器中,从而可以在service层通过@Autowired的机制进行注入。
配置解析规则定义
- 在dubbo.xsd定义dubbo相关标签
- 在dubbo.schemas定义标签的位置location
- dubbo标签处理器器配置:在spring.handlers中定义了dubbo的命名空间和标签处理器DubboNamespaceHandler的对应关系,即当遇到dubbo标签的时候,使用DubboNamespaceHandler进行处理,解析生成beanDefinition,其中DubboNamespaceHandler继承于NamespaceHandlerSupport。
解析配置文件并生成beanDefinition
在spring扫描和解析xml文件遇到dubbo标签的时候,会使用DubboNamespaceHandler进行标签处理。
- DubboNamespaceHandler:自定义了BubboBeanDefinitionParser,使用相应的解析器,解析配置文件的标签,并转换成相应的beanDefinition。
- 通过registerBeanDefinitionParser将标签名称和解析器的对应关系注册到NamespaceHandlerSupport中的parsers中,从而在spring扫描和解析xml文件遇到对应的dubbo标签时,会使用相应的DubboBeanDefinitionParser进行标签解析,生成beanDefinition。通过registerBeanDefinitionParser将标签名称和解析器的对应关系注册到NamespaceHandlerSupport中的parsers中,从而在spring扫描和解析xml文件遇到对应的dubbo标签时,会使用相应的DubboBeanDefinitionParser进行标签解析,生成beanDefinition。
如果是使用注解而不是配置文件,则使用AnnotationBeanDefinitionParser。
服务提供者提供的服务Service:ServiceBean
- ServiceBean实现ApplicationListener接口,泛型参数为ContextRefreshedEvent,从而在spring容器启动或重启时会触发。
- ServiceBean继承于ServiceConfig,调用ServiceConfig的export方法,该方法会产生该service的Invoker,即通过该Invoker调用serviceImpl的方法,其中invoker是从该service的具体实现代理ref获取:
包含setRef方法,通过ExtensionLoader注入。 - 由之前的文章分析可知,export最终会调用RegistryProtocol的export方法完成服务导出,注册到注册中心,同时会调用doLocalExport,在提供者本地生成消费者请求处理invoker。具体为根据URL确定所使用的、对应与dubbo-rpc模块的具体rpc协议protocol,如DubboProtocol,调用protocol.export创建export对象和实际的监听URL和请求处理器,DubboProtocol请求处理器的远程通讯由dubbo-remoting模块实现,源码如下:
其中invoker为2中,注册导出服务时创建的invoker。
服务消费者引用的服务Reference:ReferenceBean
- 在解析dubbo:reference时,会产生ReferenceBean的实例。ReferenceBean实现了spring的FactoryBean接口,故spring在注入bean时,在程序使用如@Autowired时,会调用getObject方法,获取对象实例,如果是singleton类,则放到spring单实例缓存池。
- ReferenceBean继承于ReferenceConfig,getObject调用ReferenceConfig的get方法,其中get为使用synchronized修饰,保证只初始化一次:
init方法底层实现核心源码如下:
其中map为该对象实例的属性和属性值,通过createProxy创建消费者调用的代理对象。createProxy的核心源码实现如下:
(1)refprotocol:根据URL的protocol获取到dubbo-rpc模块的protocol实现,调用refprotocol.refer获取对应的消费者端的调用;通过这个代理来对服务提供者或者说服务端发起RPC请求;
(2)cluster.join:如果包含多个注册中心,则调用cluster.join进行负载均衡获取一个调用;
(3)proxyFactory.getProxy(invoker):获取最终的消费者调用代理,代理提供了一个模板,最终的调用逻辑是定义在对应的Invoker的doInvoke方法,如DubboInvoker,在doInvoker中再调用dubbo-remoting模块的client进行远程通讯。
DubboBootstrap注册spring shutdownHook
这个是在dubbo被apache孵化后,加入的。包括注册spring shutdownhook和export Service,但是export Service目前没有具体实现,还是在注册ServiceBean创建bean实例时,export。
- 通过context-param的方式将dubbo引入到宿主应用中
web-fragment.xml文件:相当于web.xml的一个小片段,通过合并这个文件到web.xml,从而在宿主应用启动时,初始化DubboApplicationContextInitializer。 - 监听spring框架启动:在DubboApplicationContextInitializer初始化时,将DubboApplicationListener作为监听器,监听宿主应用的启动。
1. DubboApplicationListener监听宿主应用的启动和关闭,调用DubboBootstrap进行dubbo框架的启动和关闭。
/**• A bootstrap class to easily start and stop Dubbo via programmatic API.
• The bootstrap class will be responsible to cleanup the resources during stop.
*/
public class DubboBootstrap
核心方法
public void start() {
if (registerShutdownHookOnStart) {
registerShutdownHook();
} else {
// DubboShutdown hook has been registered in AbstractConfig,
// we need to remove it explicitly
removeShutdownHook();
}
for (ServiceConfig serviceConfig: serviceConfigList) {
serviceConfig.export();
}
}
public void stop() {
for (ServiceConfig serviceConfig: serviceConfigList) {
serviceConfig.unexport();
}
shutdownHook.destroyAll();
if (registerShutdownHookOnStart) {
removeShutdownHook();
}
}