文章目录
dubbo源码学习历史文章
DUBBO源码学习(一)spi机制
DUBBO源码学习(二)注册中心源码解析
一、DUBBO服务暴露
spring ioc容器启动的时候会同时启动dubbo容器,从2.7.5版本后增加了DubboBootstrapApplicationListener类,负责监听dubbo容器的启动事件:
/**
* The {@link ApplicationListener} for {@link DubboBootstrap}'s lifecycle when the {@link ContextRefreshedEvent}
* and {@link ContextClosedEvent} raised
*
* @since 2.7.5
*/
public class DubboBootstrapApplicationListener extends OnceApplicationContextEventListener implements Ordered {
/**
* The bean name of {@link DubboBootstrapApplicationListener}
*
* @since 2.7.6
*/
public static final String BEAN_NAME = "dubboBootstrapApplicationListener";
private final DubboBootstrap dubboBootstrap;
public DubboBootstrapApplicationListener() {
this.dubboBootstrap = DubboBootstrap.getInstance();
}
public DubboBootstrapApplicationListener(ApplicationContext applicationContext) {
super(applicationContext);
this.dubboBootstrap = DubboBootstrap.getInstance();
DubboBootstrapStartStopListenerSpringAdapter.applicationContext = applicationContext;
}
/**
* Spring ioc 容器事件监听
* @param event
*/
@Override
public void onApplicationContextEvent(ApplicationContextEvent event) {
if (DubboBootstrapStartStopListenerSpringAdapter.applicationContext == null) {
DubboBootstrapStartStopListenerSpringAdapter.applicationContext = event.getApplicationContext();
}
//容器刷新事件
if (event instanceof ContextRefreshedEvent) {
onContextRefreshedEvent((ContextRefreshedEvent) event);
//容器关闭事件
} else if (event instanceof ContextClosedEvent) {
onContextClosedEvent((ContextClosedEvent) event);
}
}
private void onContextRefreshedEvent(ContextRefreshedEvent event) {
dubboBootstrap.start();
}
private void onContextClosedEvent(ContextClosedEvent event) {
DubboShutdownHook.getDubboShutdownHook().run();
}
@Override
public int getOrder() {
return LOWEST_PRECEDENCE;
}
}
可以看到DubboBootstrapApplicationListener继承了OnceApplicationContextEventListener类,主要是实现了onApplicationContextEvent 方法,通过此方法监听了同期的刷新与关闭事件,同时也实现了Ordered接口,执行的顺序为最低顺序。
1.1、DUBBO容器的启动
DUBBO容器的启动是由DubboBootstrap来执行的。DubboBootstrap中有比较重要的两个对象,一个是ConfigManager,一个是Environment。
从上图可以看出,配置加载大概分为两个阶段:
- 第一阶段为DubboBootstrap初始化之前,在Spring context启动时解析处理XML配置/注解配置/Java-config 或者是执行API配置代码,创建config bean并且加入到ConfigManager中。
- 第二阶段为DubboBootstrap初始化过程,从配置中心读取外部配置,依次处理实例级属性配置和应用级属性配置,最后刷新所有配置实例的属性,也就是属性覆盖。
- ConfigManager:顾名思义是一个配置中心,有RegistryConfig(注册中心配置)、ConsumerConfig(消费者配置)、ProtocolConfig(协议配置)、ProviderConfig(服务提供者配置)、ApplicationConfig(容器配置)、MonitorConfig(监控中心配置)。
- Environment:Environment主要处理的与系统配置相关,比如Java系统配置,以及配置中心的配置。
DUBBO容器的启动是通过start方法执行的:
public class DubboBootstrap {
/**
* Dubbo的启动
*/
public DubboBootstrap start() {
//通过cas原子操作代替加锁
if (started.compareAndSet(false, true)) {
ready.set(false);
//初始化操作
initialize();
if (logger.isInfoEnabled()) {
logger.info(NAME + " is starting...");
}
// Dubbo Services服务暴露
exportServices();
// 是否配置了元数据中心的url
if (!isOnlyRegisterProvider() || hasExportedServices()) {
// export MetadataService 暴露本地的元数据服务
exportMetadataService();
// 将本地serviceInstance注册到注册中心
registerServiceInstance();
}
//处理ReferenceConfig对象
referServices();
//service异步暴露后的返回处理
if (asyncExportingFutures.size() > 0) {
new Thread(() -> {
try {
this.awaitFinish();
} catch (Exception e) {
logger.warn(NAME + " exportAsync occurred an exception.");
}
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready.");
}
//spi机制,获取所有DubboBootstrapStartStopListener,本包下会拿到DubboBootstrapStartStopListenerSpringAdapter类
ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
//发布DubboBootstrapStatedEvent事件
exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
}).start();
} else {
//service同步暴露处理,与上一步类似
ready.set(true);
if (logger.isInfoEnabled()) {
logger.info(NAME + " is ready.");
}
ExtensionLoader<DubboBootstrapStartStopListener> exts = getExtensionLoader(DubboBootstrapStartStopListener.class);
exts.getSupportedExtensionInstances().forEach(ext -> ext.onStart(this));
}
if (logger.isInfoEnabled()) {
logger.info(NAME + " has started.");
}
}
return this;
}
/**
* 暴露服务
*/
private void exportServices() {
// 创建的每个ServiceConfig对象都添加到configManager,下面获取所有的ServiceConfig对象并遍历
configManager.getServices().forEach(sc -> {
ServiceConfig serviceConfig = (ServiceConfig) sc;
serviceConfig.setBootstrap(this);
//异步暴露,使用线程池暴露服务
if (exportAsync) {
ExecutorService executor = executorRepository.getServiceExporterExecutor();
Future<?> future = executor.submit(() -> {
try {
//暴露服务的动作
exportService(serviceConfig);
} catch (Throwable t) {
logger.error("export async catch error : " + t.getMessage(), t);
}
});
asyncExportingFutures.add(future);
} else {
//暴露服务
exportService(serviceConfig);
}
});
}
private void exportService(ServiceConfig sc) {
if (exportedServices.containsKey(sc.getServiceName())) {
throw new IllegalStateException("There are multiple ServiceBean instances with the same service name: [" +
sc.getServiceName() + "], instances: [" +
exportedServices.get(sc.getServiceName()).toString() + ", " +
sc.toString() + "]. Only one service can be exported for the same triple (group, interface, version), " +
"please modify the group or version if you really need to export multiple services of the same interface.");
}
//服务暴露
sc.export();
//服务暴露后放入缓存,防止重复暴露
exportedServices.put(sc.getServiceName(), sc);
}
}
二、serviceConfig服务暴露
老图新用,可以看到dubbo的十层协议的第二层,就是serviceConfig.export()。通过serviceConfig.export()方法,我们可以将dubbo的服务通过不同的protocol暴露到注册中心中。
public class ServiceConfig<T> extends ServiceConfigBase<