Dubbo依赖关系
图例说明:
图中小方块Protocol, Cluster, Proxy, Service, Container, Registry, Monitor代表层或模块,蓝色的表示与业务有交互,绿色的表示只对Dubbo内部交互。
- 图中背景方块Consumer, Provider, Registry, Monitor代表部署逻辑拓普节点。
- 图中蓝色虚线为初始化时调用,红色虚线为运行时异步调用,红色实线为运行时同步调用。
- 图中只包含RPC的层,不包含Remoting的层,Remoting整体都隐含在Protocol中。
本文将结合Dubbo源码来分析 Dubbo服务提供者(Service Provider)的创建和暴露。
Dubbo 集成Spring Framework
Dubbo 支持集成Spring Framework,这可能也是最常用的开发方式。当然Spring 不是必须的 Dubbo的官方文档也说明了,Dubbo可以不依赖任何Spring。
dubbo-demo-provider.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<dubbo:application name="dubbo-demo-provider"/>
<dubbo:registry address="zookeeper://224.5.6.7:2181"/>
<dubbo:protocol id="dubbo" name="dubbo" port="20880" />
<bean id="demoService" class="com.alibaba.dubbo.sample.DemoServiceImpl"/>
<dubbo:service protocol="dubbo" interface="com.alibaba.dubbo.sample.DemoService" ref="demoService"/>
</beans>
首先,是 <dubbo:service />
这个是Spring Framework 预留的扩展功能,详细的说明参考 Spring XML Extensions,实现起来也很简单:
- 编写自己的 XML schema
- 自定义 NamespaceHandler;
- 注册NamespaceHandler 和 schema
Spring默认会在加载jar包下的 META-INF/spring.handlers文件下寻找NamespaceHandler,在 META-INF/spring.schemas 文件下查找schema 。
DubboNamespaceHandler 源码如下:
public class DubboNamespaceHandler extends NamespaceHandlerSupport {
static {
Version.checkDuplicate(DubboNamespaceHandler.class);
}
public void init() {
registerBeanDefinitionParser("application", new DubboBeanDefinitionParser(ApplicationConfig.class, true));
registerBeanDefinitionParser("module", new DubboBeanDefinitionParser(ModuleConfig.class, true));
registerBeanDefinitionParser("registry", new DubboBeanDefinitionParser(RegistryConfig.class, true));
registerBeanDefinitionParser("monitor", new DubboBeanDefinitionParser(MonitorConfig.class, true));
registerBeanDefinitionParser("provider", new DubboBeanDefinitionParser(ProviderConfig.class, true));
registerBeanDefinitionParser("consumer", new DubboBeanDefinitionParser(ConsumerConfig.class, true));
registerBeanDefinitionParser("protocol", new DubboBeanDefinitionParser(ProtocolConfig.class, true));
registerBeanDefinitionParser("service", new DubboBeanDefinitionParser(ServiceBean.class, true));
registerBeanDefinitionParser("reference", new DubboBeanDefinitionParser(ReferenceBean.class, false));
registerBeanDefinitionParser("annotation", new DubboBeanDefinitionParser(AnnotationBean.class, true));
}
}
给出的BeanDefinitionParser全部是DubboBeanDefinitionParser,如果我们想看看<dubbo:registry>是怎么解析的,就可以去看看DubboBeanDefinitionParser的源代码。
DubboBeanDefinitionParser 具体解析过程就不再说明了,结果就是不同的配置分别转换成Spring容器中的一个bean对象。
- application 对应ApplicationConfig
- registry 对应RegistryConfig
- monitor 对应MonitorConfig
- provider 对应ProviderConfig
- consumer 对应ConsumerConfig
- protocol 对应ProtocolConfig
- service 对应ServiceBean
- reference 对应ReferenceBean
- annotation对应AnnotationBean
为了在Spring启动的时候,也相应的启动provider发布服务注册服务的过程:又加入了一个和Spring相关联的ServiceBean,继承了ServiceConfig并实现了InitializingBean接口,如下:
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware {
}
为了在Spring启动的时候,也相应的启动consumer发现服务的过程:又加入了一个和Spring相关联的ReferenceBean,继承了ReferenceConfig并实现了 FactoryBean接口,如下:
public class ReferenceBean<T> extends ReferenceConfig<T> implements FactoryBean, ApplicationContextAware, InitializingBean, DisposableBean {
}
ServiceBean、ReferenceBean和AnnotationBean 专门为了和Spring Framework 来集成。如果不想依赖Spring,我们就可以手动来创建上述配置对象,通过ServiceConfig和ReferenceConfig的API来启动相应的服务。
服务的发布过程
通过上面的分析,Dubbo通过Spring的解析收集到很多一些配置,然后将这些配置都存至ServiceConfig中,然后调用ServiceConfig的export()方法来进行服务的发布与注册。
ServiceBean代码如下:
public class ServiceBean<T> extends ServiceConfig<T> implements InitializingBean, DisposableBean, ApplicationContextAware, ApplicationListener, BeanNameAware {
public void onApplicationEvent(ApplicationEvent event) {
if (ContextRefreshedEvent.class.getName().equals(event.getClass().getName())) {
if (isDelay() && ! isExported() && ! isUnexported()) {
if (logger.isInfoEnabled()) {
logger.info("The service ready on spring started. service: " + getInterface());
}
export();
}
}
}
private boolean isDelay() {
Integer delay = getDelay();
ProviderConfig provider = getProvider();
if (delay == null && provider != null) {
delay = provider.getDelay();
}
return supportedApplicationListener && (delay == null || delay.intValue() == -1);
}
@SuppressWarnings({ "unchecked", "deprecation" })
public void afterPropertiesSet() throws Exception {
if (getProvider() == null) {
}
if (getApplication() == null
&& (getProvider() == null || getProvider().getApplication() == null)) {
}
if (getModule() == null
&& (getProvider() == null || getProvider().getModule() == null)) {
}
if ((getRegistries() == null || getRegistries().size() == 0)
&& (getProvider() == null || getProvider().getRegistries() == null || getProvider().getRegistries().size() == 0)
&& (getApplication() == null || getApplication().getRegistries() == null || getApplication().getRegistries().size() == 0)) {
}
if (getMonitor() == null
&& (getProvider() == null || getProvider().getMonitor() == null)
&& (getApplication() == null || getApplication().getMonitor() == null)) {
}
if ((getProtocols() == null || getProtocols().size() == 0)
&& (getProvider() == null || getProvider().getProtocols() == null || getProvider().getProtocols().size() == 0)) {
}
if (getPath() == null || getPath().length() == 0) {
}
if (! isDelay()) {
export(); //暴露服务
}
}
public void destroy() throws Exception {
unexport();
}
}
此处 export()方法是从 ServiceConfig类继承来的,ServiceConfig如下:
public class ServiceConfig<T> extends AbstractServiceConfig {
private static final long serialVersionUID = 3033787999037024738L;
private static final Protocol protocol = ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
private static final Map<String, Integer> RANDOM_PORT_MAP = new HashMap<String, Integer>();
// 接口类型
private String interfaceName;
private Class<?> interfaceClass;
// 接口实现类引用
private T ref;
// 服务名称
private String path;
// 方法配置
private List<MethodConfig> methods;
private ProviderConfig provider;
private final List<URL> urls = new ArrayList<URL>();
private final List<Exporter<?>> exporters = new ArrayList<Exporter<?>>();
private transient volatile boolean exported;
private transient volatile boolean unexported;
private volatile String generic;
//暴露服务
public synchronized void export() {
if (provider != null) {
if (export == null) {
export = provider.getExport();
}
if (delay == null) {
delay = provider.getDelay();
}
}
if (export != null && ! export.booleanValue()) {
return;
}
if (delay != null && delay > 0) {
Thread thread = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(delay);
} catch (Throwable e) {
}
doExport();
}
});
thread.setDaemon(true);
thread.setName("DelayExportServiceThread");
thread.start();
} else {
doExport();
}
}
protected synchronized void doExport() {
if (unexported) {
throw new IllegalStateException("Already unexported!");
}
if (exported) {
return;
}
exported = true;
if (interfaceName == null || interfaceName.length() == 0) {
throw new IllegalStateException("<dubbo:service interface=\"\" /> interface not allow null!");
}
checkDefault();
checkApplication();
checkRegistry();
checkProtocol();
appendProperties(this);
checkStubAndMock(interfaceClass);
if (path == null || path.length() == 0) {
path = interfaceName;
}
doExportUrls();
}
//根据配置的协议暴露服务
private void doExportUrls() {
List<URL> registryURLs = loadRegistries(true);
for (ProtocolConfig protocolConfig : protocols) {
doExportUrlsFor1Protocol(protocolConfig, registryURLs);
}
}
//关闭服务
public synchronized void unexport() {
if (! exported) {
return;
}
if (unexported) {
return;
}
if (exporters != null && exporters.size() > 0) {
for (Exporter<?> exporter : exporters) {
try {
exporter.unexport();
} catch (Throwable t) {
logger.warn("unexpected err when unexport" + exporter, t);
}
}
exporters.clear();
}
unexported = true;
}
}
Dubbo的核心领域模型
Dubbo 几个核心的领域模型:
- Invoker是实体域,它是Dubbo的核心模型,其它模型都向它靠扰,或转换成它,它代表一个可执行体,可向它发起invoke调用,它有可能是一个本地的实现,也可能是一个远程的实现,也可能一个集群实现。
- Protocol是服务域,它是Invoker暴露和引用的主功能入口,它负责Invoker的生命周期管理。
- Invocation是会话域,它持有调用过程中的变量,比如方法名,参数等。