es 使用google开源的依赖注入框架guice,这个项目号称比spring快100倍,不过由于其代码比较简洁,这样的结论是很有可能的。es 是直接把guice的源码放到自己的包内(es把很多开源项目的代码都直接集成到自己项目中,省得依赖一堆的jar包,也使es的jar包达到差不多10M),它位于 org.elasticsearch.common.inject 目录下。
es 里面的组件基本都实现了模块化管理,对guice进行了简单的封装,通过 ModulesBuilder 类构建es的模块,一个es节点模块有:
//源自org.elasticsearch.common.inject;
public class ModulesBuilder implements Iterable<Module> {
private final List<Module> modules = new ArrayList<>();
public ModulesBuilder add(Module... newModules) {
Collections.addAll(modules, newModules);
return this;
}
@Override
public Iterator<Module> iterator() {
return modules.iterator();
}
public Injector createInjector() {
Injector injector = Guice.createInjector(modules);
((InjectorImpl) injector).clearCache();
// in ES, we always create all instances as if they are eager singletons
// this allows for considerable memory savings (no need to store construction info) as well as cycles
((InjectorImpl) injector).readOnlyAllSingletons();
return injector;
}
}
//通过下面伪代码进行模块化
ModulesBuilder modules = new ModulesBuilder();
modules.add(new ToolModule());
modules.add(new HumanModule());
Injector injector = modules.createInjector(); // 注入所有module下的实例
Person instance = injector.getInstance(Person.class);
- PluginsModule:插件模块
- SettingsModule:设置参数模块
- NodeModule:节点模块
- NetworkModule:网络模块
- NodeCacheModule:缓存模块
- ScriptModule:脚本模块
- JmxModule:jmx模块
- EnvironmentModule:环境模块
- NodeEnvironmentModule:节点环境模块
- ClusterNameModule:集群名模块
- ThreadPoolModule:线程池模块
- DiscoveryModule:自动发现模块
- ClusterModule:集群模块
- RestModule:rest模块
- TransportModule:tcp模块
- HttpServerModule:http模块
- IndicesModule:索引模块
- SearchModule:搜索模块
- ActionModule:行为模块
- MonitorModule:监控模块
- GatewayModule:持久化模块
- NodeClientModule:客户端模块
下面就TransportModule的 TransportClient 初始化情况展开说明:
public TransportClient build() {
Settings settings = InternalSettingsPreparer.prepareSettings(this.settings);
settings = settingsBuilder()
.put(NettyTransport.PING_SCHEDULE, "5s") // enable by default the transport schedule ping interval
.put(settings)
.put("network.server", false)
.put("node.client", true)
.put(CLIENT_TYPE_SETTING, CLIENT_TYPE)
.build();
PluginsService pluginsService = new PluginsService(settings, null, null, pluginClasses);
this.settings = pluginsService.updatedSettings();
Version version = Version.CURRENT;
final ThreadPool threadPool = new ThreadPool(settings);
NamedWriteableRegistry namedWriteableRegistry = new NamedWriteableRegistry();
boolean success = false;
try {
ModulesBuilder modules = new ModulesBuilder();
modules.add(new Version.Module(version));
// plugin modules must be added here, before others or we can get crazy injection errors...
for (Module pluginModule : pluginsService.nodeModules()) {
modules.add(pluginModule);
}
modules.add(new PluginsModule(pluginsService));
modules.add(new SettingsModule(this.settings));
modules.add(new NetworkModule(namedWriteableRegistry));
modules.add(new ClusterNameModule(this.settings));
modules.add(new ThreadPoolModule(threadPool));
modules.add(new TransportModule(this.settings, namedWriteableRegistry));
modules.add(new SearchModule() {
@Override
protected void configure() {
// noop
}
});
modules.add(new ActionModule(true));
modules.add(new ClientTransportModule(hostFailedListener));
modules.add(new CircuitBreakerModule(this.settings));
pluginsService.processModules(modules);
Injector injector = modules.createInjector();
final TransportService transportService = injector.getInstance(TransportService.class);
transportService.start();
transportService.acceptIncomingRequests();
TransportClient transportClient = new TransportClient(injector); // 初始化TransportClient对象
success = true;
return transportClient;
} finally {
if (!success) {
ThreadPool.terminate(threadPool, 10, TimeUnit.SECONDS);
}
}
}
//settings模块,源自org.elasticsearch.common.settings
public class SettingsModule implements Module {
public SettingsModule(Settings settings, Setting<?>... additionalSettings) {
this(settings, Arrays.asList(additionalSettings), Collections.emptyList());
}
@Override
public void configure(Binder binder) {
binder.bind(Settings.class).toInstance(settings);
binder.bind(SettingsFilter.class).toInstance(settingsFilter);
binder.bind(ClusterSettings.class).toInstance(clusterSettings);
binder.bind(IndexScopedSettings.class).toInstance(indexScopedSettings);
}
}
看到了吧,es的模块化的解决方案主要是依靠Guice,而优秀的java的模块化解决方案也是我们值得学习与借鉴的。
引用资料