上一篇文章,我们分析了 Dubbo 3.2 版本在 Provider 启动前的操作流程,这次我们具体分析具体它的启动过程,揭开它的神秘面纱。
这里我们还是以provider启动的Demo为入口,进行分析。如下,为Dubbo服务暴漏出来的接口:
public interface DemoService {
String sayHello(String name);
}
DemoServiceImpl为Dubbo provider
public class DemoServiceImpl implements DemoService {
private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);
@Override
public String sayHello(String name) {
logger.info("Hello " + name + ", request from consumer: "
+ RpcContext.getServiceContext().getRemoteAddress());
return "Hello " + name + ", response from provider: "
+ RpcContext.getServiceContext().getLocalAddress();
}
}
Application为服务的启动类
public class Application {
private static final String REGISTRY_URL = "zookeeper://sr-1-zk-cluster-1.gz.cvte.cn:2181";
public static void main(String[] args) {
startWithBootstrap();
}
private static void startWithBootstrap() {
ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();
service.setInterface(DemoService.class);
service.setRef(new DemoServiceImpl());
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
bootstrap
.application(new ApplicationConfig("dubbo-api-provider"))
.registry(new RegistryConfig(REGISTRY_URL))
.protocol(new ProtocolConfig(CommonConstants.DUBBO, -1))
.service(service)
.start()
.await();
}
}
上文分析过设置 application -> 设置 registry -> 设置 protocol -> 设置 serviceConfig 的流程了,这次我们进入 start 方法。
public DubboBootstrap start() {
this.start(true);
return this;
}
/**
* Start dubbo application
*
* @param wait If true, wait for startup to complete, or else no waiting.
* @return
*/
public DubboBootstrap start(boolean wait) {
Future future = applicationDeployer.start();
if (wait) {
try {
future.get();
} catch (Exception e) {
throw new IllegalStateException("await dubbo application start finish failure", e);
}
}
return this;
}
private volatile DeployState state = PENDING;
private final List moduleModels = new CopyOnWriteArrayList<>();
public Future start() {
synchronized (startLock) {
if (isStopping() || isStopped() || isFailed()) {
throw new IllegalStateException(getIdentifier() + " is stopping or stopped, can not start again");
}
try {
// maybe call start again after add new module, check if any new module
boolean hasPendingModule = hasPendingModule();
if (isStarting()) {
// currently, is starting, maybe both start by module and application
// if it has new modules, start them
if (hasPendingModule) {
startModules();
}
// if it is starting, reuse previous startFuture
return startFuture;
}
// if is started and no new module, just return
if (isStarted() && !hasPendingModule) {
return CompletableFuture.completedFuture(false);
}
// pending -> starting : first start app
// started -> starting : re-start app
onStarting();
initialize();
doStart();
} catch (Throwable e) {
onFailed(getIdentifier() + " start failure", e);
throw e;
}
return startFuture;
}
}
private boolean hasPendingModule() {
boolean found = false;
for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
if (moduleModel.getDeployer().isPending()) {
found = true;
break;
}
}
return found;
}
protected List<DeployListener> listeners = new CopyOnWriteArrayList<>();
DubboBootstrap bootstrap = DubboBootstrap.getInstance();
private volatile CompletableFuture startFuture;
private void onStarting() {
// pending -> starting
// started -> starting
if (!(isPending() || isStarted())) {
return;
}
setStarting();
startFuture = new CompletableFuture();
if (logger.isInfoEnabled()) {
logger.info(getIdentifier() + " is starting.");
}
}
protected void setStarting() {
this.state = STARTING;
for (DeployListener<E> listener : listeners) {
try {
listener.onStarting(scopeModel);
} catch (Throwable e) {
logger.error(
COMMON_MONITOR_EXCEPTION,
"",
"",
getIdentifier() + " an exception occurred when handle starting event",
e);
}
}
}
// DeployListenerAdapter
applicationDeployer.addDeployListener(new DeployListenerAdapter<ApplicationModel>() {
@Override
public void onStarted(ApplicationModel scopeModel) {
notifyStarted(applicationModel);
}
@Override
public void onStopped(ApplicationModel scopeModel) {
notifyStopped(applicationModel);
}
@Override
public void onFailure(ApplicationModel scopeModel, Throwable cause) {
notifyStopped(applicationModel);
}
});
// ExporterDeployListener
public class ExporterDeployListener implements ApplicationDeployListener, Prioritized {
protected volatile ConfigurableMetadataServiceExporter metadataServiceExporter;
@Override
public void onInitialize(ApplicationModel scopeModel) {}
@Override
public void onStarting(ApplicationModel scopeModel) {
}
// ....
}
private void doStart() {
startModules();
}
private void startModules() {
// ensure init and start internal module first
prepareInternalModule();
// filter and start pending modules, ignore new module during starting, throw exception of module start
for (ModuleModel moduleModel : applicationModel.getModuleModels()) {
if (moduleModel.getDeployer().isPending()) {
moduleModel.getDeployer().start();
}
}
}
本文分析了 Dubbo 3.2 版本分析Provider启动时的流程,会先启动 ApplicationDeployer 类型实例,在执行 state( onStarting 方法) 更新流程后,进行初始化**( initialize 方法),最后然后是执行启动流程( do start 方法)**。在 do start 方法里才又先启动我们的内部模块,再遍历所有的模块列表,把所有处于准备状态的模块进行启动。最后,关于 initialize 方法由于涉及流程很长,为了保证文章可读性,这里笔者暂时先不展开,也算留个悬念,下一篇我们继续分析它。