Druid源码阅读——Server启动流程
Druid的代码里面使用了大量的Google Guice依赖注入(DI),还是第一次接触Guice。相比于Spring的DI,这是一个更加轻量的注入方案。如果不了解它的工作流程,代码阅读理解起来还是有点困难的,找不到头尾。这里以CliOverlord为例子,看一下服务的启动流程。Druid版本是0.13.0。
类继承图
CliOverlord类继承图先来看一下CliOverlord的类继承关系图。Command注解来自命令行处理库Airline,有兴趣的可以深入了解一下。GuiceRunnable是所有服务的基类,从名字可以看出,这里主要还是定义了一些依赖注入处理的逻辑,核心是makeInjector和initLifecycle这两个方法。GuiceRunnable的子类通过重写getModules方法,来定义服务自己特有的装配逻辑,并实现Lifecycle.Handler接口,用于Lifecycle回调。出了实现Handler接口,lifecycle也会扫描注入的依赖中的方法或者注解,如果包含start/stop方法或者有被LifecycleStart/LifecycleStop注解修饰的方法,也会调用相应的方法来启动或者停止服务组件。
ServerRunnable继承GuiceRunnable,实现了Runnable接口的run方法。实现逻辑只是简单的调用父类的makeInjector和initLifecycle方法。除此之外还新增了一个DiscoverySideEffectsProvider类,实现的是Guice的Provider接口,用于将不同类型的Druid节点注册到zk或者从zk注销,提供服务发现的功能。不同类型的Druid服务继承ServerRunnable,一般只需重写getModules方法绑定依赖关系即可。
CliOverlord启动流程
org.apache.druid.cli.Main server overlord
这是启动overlord服务的命令,通过airline解析命令参数后,会调用到类CliOverlord的run方法,run方法里面进一步调用父类的makeInjector方法,在获取注入器(Injector)时,定义了一些所有服务共同拥有的Modules(defaultModules),其中就有JettyServerModule用于启动web server。这个JettyServerModule内部实现了Lifecycle.Handler(实现start和stop方法),Lifecycle会回调启动和停止方法管理。对于服务中包含哪些servlet则是在每个服务的实现重写getModules的时候,通过Jerseys.addResource方法指定,比如CliOverlord增加了如下三个resource:
Jerseys.addResource(binder, OverlordResource.class);
Jerseys.addResource(binder, SupervisorResource.class);
Jerseys.addResource(binder, HttpRemoteTaskRunnerResource.class);
OverlordResource就是提供/druid/indexer/v1/task服务的地方。
总结
从分析来看,Druid在代码实现上统一了服务的启动流程,尽可能的复用流程和代码,其他druid节点的启动流程是类似的。很像Hook机制,用户只需要实现handler中的方法,处理流程会回调这些方法。