本文基于dubbo 2.7.5版本代码
DubboBootstrap启动过程详解
- 一、触发DubboBootstrap启动
- 二、start方法详解
- 1、initialize方法
- 2、exportServices方法
- 3、isOnlyRegisterProvider方法
- 4、hasExportedServices方法
- 5、exportMetadataService方法
- 6、registerServiceInstance方法
- 7、referServices方法
DubboBootstrap的启动是由start方法完成的,start方法的执行成功,意味着dubbo的启动结束。服务端服务的暴露就是在start方法中完成的。
一、触发DubboBootstrap启动
dubbo启动的时候,将DubboBootstrapApplicationListener注册为监听器,监听ContextRefreshedEvent事件。代码如下:
public void onApplicationContextEvent(ApplicationContextEvent event) {
if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}
//监听ContextRefreshedEvent事件
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();//调用start方法
}
从上面代码可以看出,当发生ContextRefreshedEvent事件的时候,dubbo调用DubboBootstrap的start方法。
二、start方法详解
下面分析一下start方法(代码有删减)。
public DubboBootstrap start() {
//只能初始化一次
if (started.compareAndSet(false, true)) {
initialize();//调用初始化方法
// 1. export Dubbo Services
exportServices();
// Not only provider register
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// 2. export MetadataService
exportMetadataService();
//3. Register the local ServiceInstance if required
registerServiceInstance();
}
referServices();
}
return this;
}
1、initialize方法
在start方法中,也会调用initialize方法,之前提到过,服务端启动的时候,dubbo在start方法中调用initialize方法做初始化,而客户端启动的时候会跳过initialize方法。
2、exportServices方法
initialize方法之后调用exportServices方法,该方法用于暴露服务,服务端使用。
private void exportServices() {
//创建的每个ServiceConfig对象都添加到configManager,下面获取所有的ServiceConfig对象并遍历
configManager.getServices().forEach(sc -> {
// TODO, compatible with ServiceConfig.export()
ServiceConfig serviceConfig = (ServiceConfig) sc;
serviceConfig.setBootstrap(this);
if (exportAsync) {//异步暴露,使用线程池暴露服务
ExecutorService executor = executorRepository.getServiceExporterExecutor();
Future<?> future = executor.submit(() -> {
sc.export();//暴露服务
});
asyncExportingFutures.add(future);
} else {
sc.export();//暴露服务,export方法以后文章介绍
exportedServices.add(sc);//记录所有暴露的服务
}
});
}
3、isOnlyRegisterProvider方法
isOnlyRegisterProvider方法检查ApplicationConfig的registerConsumer属性,从代码分析,registerConsumer只是用于在这里做了判断,我认为该属性无用,可以不用配置。
4、hasExportedServices方法
hasExportedServices()检查是否配置元数据中心的url,如果配置了,返回true。
5、exportMetadataService方法
exportMetadataService方法用于暴露本地元数据服务,在《dubbo解析-DubboBootstrap(二)》的文章里面介绍了方法initMetadataServiceExporter,initMetadataServiceExporter方法里面建立了对象metadataServiceExporter,然后在这里暴露服务。服务暴露后客户端可以使用MetadataService接口方法查看dubbo实例的元数据,服务是以dubbo服务形式发布的。关于MetadataService以后文章介绍。
private void exportMetadataService() {
metadataServiceExporter.export();
}
6、registerServiceInstance方法
registerServiceInstance用于将dubbo实例注册到专用于服务发现的注册中心。
private void registerServiceInstance() {
if (CollectionUtils.isEmpty(getServiceDiscoveries())) {
return;
}
ApplicationConfig application = getApplication();
String serviceName = application.getName();
URL exportedURL = selectMetadataServiceExportedURL();
String host = exportedURL.getHost();
int port = exportedURL.getPort();
//创建ServiceInstance对象,该对象中持有下面方法的入参值,以及注册中心的类型,默认是local。ServiceInstance代表了一个dubbo实例,其他dubbo实例可以通过ServiceInstance的属性信息找到本实例的位置
ServiceInstance serviceInstance = createServiceInstance(serviceName, host, port);
//获取所有的注册中心,将ServiceInstance对象注册到注册中心,这里的注册中心实现了ServiceDiscovery接口,是专用于服务发现的。
getServiceDiscoveries().forEach(serviceDiscovery -> serviceDiscovery.register(serviceInstance));
}
7、referServices方法
referServices方法用于处理ReferenceConfig对象,但是这里有个问题。
private void referServices() {
if (cache == null) {
cache = ReferenceConfigCache.getCache();
}
configManager.getReferences().forEach(rc -> {
// TODO, compatible with ReferenceConfig.refer()
ReferenceConfig referenceConfig = (ReferenceConfig) rc;
referenceConfig.setBootstrap(this);
if (rc.shouldInit()) {
if (referAsync) {
CompletableFuture<Object> future = ScheduledCompletableFuture.submit(
executorRepository.getServiceExporterExecutor(),
() -> cache.get(rc)
);
asyncReferringFutures.add(future);
} else {
cache.get(rc);
}
}
});
}
可以看到,上面的代码遍历的ReferenceConfig对象列表是从configManager中获取的,一般的XXXConfig对象是由spring容器创建的,每个对象都会加入到configManager中(可以查看方法addIntoConfigManager),但是ReferenceConfig对象的创建有点特殊,该对象是由ReferenceBeanBuilder创建的:
protected ReferenceBean doBuild() {
return new ReferenceBean<Object>();
}
所以ReferenceConfig对象没有加入到configManager中,因此referServices方法没有任何作用。