elasticsearch通過guice注入Node組裝啟動過程
elasticsearch啟動過程
elasticsearch的啟動過程是根據(jù)配置和環(huán)境組裝需要的模塊并啟動的過程。這一過程就是通過guice注入各個功能模塊并啟動這些模塊,從而得到一個功能完整的node。正如之前所說elasticsearch的模塊化特點,它的各個功能都是獨立實現(xiàn),然后實現(xiàn)通過guice對外提供。
首先簡單的說一下guice,它是google的一個輕量級依賴注入框架。它的作者也是依賴注入標(biāo)準(zhǔn)(JSR-330)制定者。雖然它是輕量級框架,但是它的功能及性能卻非常好,這也是elasticsearch選用它作為代碼主要框架的一個主要原因。它的使用請參考它的用戶指導(dǎo)。
首先看一下node的初始化
node接口的唯一實現(xiàn)是InternalNode,它的初始化代碼如下所示:
public InternalNode(Settings preparedSettings, boolean loadConfigSettings) throws ElasticsearchException {
final Settings pSettings = settingsBuilder().put(preparedSettings)
.put(Client.CLIENT_TYPE_SETTING, CLIENT_TYPE).build();
Tuple<Settings, Environment> tuple = InternalSettingsPreparer.prepareSettings(pSettings, loadConfigSettings);
tuple = new Tuple<>(TribeService.processSettings(tuple.v1()), tuple.v2());
logger.info("initializing ...");
//啟動插件service,加載并啟動插件
this.pluginsService = new PluginsService(tuple.v1(), tuple.v2());
this.settings = pluginsService.updatedSettings();
// create the environment based on the finalized (processed) view of the settings
this.environment = new Environment(this.settings());
CompressorFactory.configure(settings);
//配置node環(huán)境
final NodeEnvironment nodeEnvironment;
try {
nodeEnvironment = new NodeEnvironment(this.settings, this.environment);
} catch (IOException ex) {
throw new ElasticsearchIllegalStateException("Failed to created node environment", ex);
}
boolean success = false;
try {
//加載各個模塊
ModulesBuilder modules = new ModulesBuilder();
modules.add(new Version.Module(version));
modules.add(new CacheRecyclerModule(settings));
modules.add(new PageCacheRecyclerModule(settings));
modules.add(new CircuitBreakerModule(settings));
modules.add(new BigArraysModule(settings));
modules.add(new PluginsModule(settings, pluginsService));
modules.add(new SettingsModule(settings));
modules.add(new NodeModule(this));
modules.add(new NetworkModule());
modules.add(new ScriptModule(settings));
modules.add(new EnvironmentModule(environment));
……
}可以看到node的初始化過程主要包括三部分
第一是啟動插件服務(wù)(es提供了插件功能來進行擴展功能,這也是它的一個亮點),加載需要的插件
第二是配置node環(huán)境
最后就是通過guice加載各個模塊。
啟動各個模塊的過程
插件服務(wù)稍微復(fù)雜最后再說。elasticsearch各個功能模塊實現(xiàn)的非常好,解耦非常完美,很多模塊都實現(xiàn)了生命周期接口,只有啟動它才能夠?qū)ν馓峁┓?wù),它的啟動過程也是功能模塊初始化的過程。因此,node節(jié)點的啟動過程也就是這些模塊初始化的過程。如下面的代碼片段所示:
public Node start() {
if (!lifecycle.moveToStarted()) {
return this;
}// hack around dependency injection problem (for now...)
injector.getInstance(Discovery.class).setAllocationService(injector.getInstance(AllocationService.class));
for (Class<? extends LifecycleComponent> plugin : pluginsService.services()) {
injector.getInstance(plugin).start();
}
//通過guice獲取各個模塊的service接口并啟動
injector.getInstance(MappingUpdatedAction.class).start();
injector.getInstance(IndicesService.class).start();
injector.getInstance(IndexingMemoryController.class).start();
injector.getInstance(IndicesClusterStateService.class).start();
injector.getInstance(IndicesTTLService.class).start();
injector.getInstance(RiversManager.class).start();
injector.getInstance(SnapshotsService.class).start();
injector.getInstance(TransportService.class).start();
……
}每個模塊service都會實現(xiàn)一個start接口,模塊功能初始化過程都是這這個函數(shù)中實現(xiàn)。每個模塊的具體啟動過程后面會有涉及,這里就不做深入分析。
插件的加載過程
每個node在加載各個模塊前,會首先加載所需要的插件,如果有些插件加載不成功node會啟動失敗。這里會加載三類插件:首先是配置插件,配置到節(jié)點配置文件中插件,如分詞插件等;然后查找classpath中能找到的插件,這些插件一般防止在plugin文件夾中;最后是加載site插件,site插件是不涉及java代碼的純網(wǎng)站式插件,如監(jiān)控插件head,bigdesk等。任何使用者都可以開發(fā)自己需要的插件,只要按著elasticsearch相關(guān)版本的插件開發(fā)規(guī)范來實現(xiàn)即可。
public PluginsService(Settings settings, Environment environment) {
super(settings);
this.environment = environment;
……
ImmutableList.Builder<Tuple<PluginInfo, Plugin>> tupleBuilder = ImmutableList.builder();
// 加載配置插件
String[] defaultPluginsClasses = settings.getAsArray("plugin.types");
for (String pluginClass : defaultPluginsClasses) {
Plugin plugin = loadPlugin(pluginClass, settings);
PluginInfo pluginInfo = new PluginInfo(plugin.name(), plugin.description(), hasSite(plugin.name()), true, PluginInfo.VERSION_NOT_AVAILABLE);
if (logger.isTraceEnabled()) {
logger.trace("plugin loaded from settings [{}]", pluginInfo);
}
tupleBuilder.add(new Tuple<>(pluginInfo, plugin));
}
// 查找classpatch中的所有插件
loadPluginsIntoClassLoader();
if (loadClasspathPlugins) {
tupleBuilder.addAll(loadPluginsFromClasspath(settings));
}
this.plugins = tupleBuilder.build();
// We need to build a List of jvm and site plugins for checking mandatory plugins
Map<String, Plugin> jvmPlugins = Maps.newHashMap();
List<String> sitePlugins = Lists.newArrayList();
for (Tuple<PluginInfo, Plugin> tuple : this.plugins) {
jvmPlugins.put(tuple.v2().name(), tuple.v2());
if (tuple.v1().isSite()) {
sitePlugins.add(tuple.v1().getName());
}
}
// 加載site插件
ImmutableList<Tuple<PluginInfo, Plugin>> tuples = loadSitePlugins();
for (Tuple<PluginInfo, Plugin> tuple : tuples) {
sitePlugins.add(tuple.v1().getName());
}
// 檢驗代理插件,如果有加載不成功的插件就拋出異常,停止node啟動。
String[] mandatoryPlugins = settings.getAsArray("plugin.mandatory", null);
if (mandatoryPlugins != null) {
Set<String> missingPlugins = Sets.newHashSet();
for (String mandatoryPlugin : mandatoryPlugins) {
if (!jvmPlugins.containsKey(mandatoryPlugin) && !sitePlugins.contains(mandatoryPlugin) && !missingPlugins.contains(mandatoryPlugin)) {
missingPlugins.add(mandatoryPlugin);
}
}
if (!missingPlugins.isEmpty()) {
throw new ElasticsearchException("Missing mandatory plugins [" + Strings.collectionToDelimitedString(missingPlugins, ", ") + "]");
}
}
……
}以上就是pluginservice的初始化過程,在它的初始化過程中,加載所有能夠找的插件。插件的啟動在其他功能模塊之前,些插件,如分詞插件,啟動不成功則會對節(jié)點的功能造成影響,因此會在這里就中斷節(jié)點的啟動過程讓用戶知道。這就是節(jié)點的啟動過程。插件加載成功,各個功能模塊加載并啟動成功,節(jié)點就啟動成功。
限于篇幅這里模塊相關(guān)詳情都沒有進行深入在接下來模塊分析中會一一分析,希望大家以后多多支持腳本之家!
相關(guān)文章
基于Redis分布式鎖Redisson及SpringBoot集成Redisson
這篇文章主要介紹了基于Redis分布式鎖Redisson及SpringBoot集成Redisson,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的小小伙伴可以參考一下2022-09-09
Java8新特性Stream流中anyMatch和allMatch和noneMatch的區(qū)別解析
這篇文章主要介紹了Java8新特性Stream流中anyMatch和allMatch和noneMatch的區(qū)別解析,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01
Java實現(xiàn)批量向mysql寫入數(shù)據(jù)的方法
這篇文章主要介紹了Java實現(xiàn)批量向mysql寫入數(shù)據(jù)的方法,涉及java基于JDBC連接mysql數(shù)據(jù)庫及寫入數(shù)據(jù)的相關(guān)操作技巧,非常簡單實用,需要的朋友可以參考下2017-12-12
Mybatis插件PageHelper的實現(xiàn)原理詳解
PageHelper 是一款開源的 MyBatis 分頁插件,可以在實際應(yīng)用中方便地實現(xiàn)分頁功能,這篇文章主要來和大家講講PageHelper的原理與使用,需要的可以參考下2023-06-06
完全解析Java編程中finally語句的執(zhí)行原理
這篇文章主要深度介紹了Java編程中finally語句的執(zhí)行原理,細(xì)致講解了finally在異常處理中的流程控制作用,需要的朋友可以參考下2015-11-11

