elasticsearch通過(guò)guice注入Node組裝啟動(dòng)過(guò)程
elasticsearch啟動(dòng)過(guò)程
elasticsearch的啟動(dòng)過(guò)程是根據(jù)配置和環(huán)境組裝需要的模塊并啟動(dòng)的過(guò)程。這一過(guò)程就是通過(guò)guice注入各個(gè)功能模塊并啟動(dòng)這些模塊,從而得到一個(gè)功能完整的node。正如之前所說(shuō)elasticsearch的模塊化特點(diǎn),它的各個(gè)功能都是獨(dú)立實(shí)現(xiàn),然后實(shí)現(xiàn)通過(guò)guice對(duì)外提供。
首先簡(jiǎn)單的說(shuō)一下guice,它是google的一個(gè)輕量級(jí)依賴注入框架。它的作者也是依賴注入標(biāo)準(zhǔn)(JSR-330)制定者。雖然它是輕量級(jí)框架,但是它的功能及性能卻非常好,這也是elasticsearch選用它作為代碼主要框架的一個(gè)主要原因。它的使用請(qǐng)參考它的用戶指導(dǎo)。
首先看一下node的初始化
node接口的唯一實(shí)現(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 ..."); //啟動(dòng)插件service,加載并啟動(dòng)插件 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 { //加載各個(gè)模塊 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的初始化過(guò)程主要包括三部分
第一是啟動(dòng)插件服務(wù)(es提供了插件功能來(lái)進(jìn)行擴(kuò)展功能,這也是它的一個(gè)亮點(diǎn)),加載需要的插件
第二是配置node環(huán)境
最后就是通過(guò)guice加載各個(gè)模塊。
啟動(dòng)各個(gè)模塊的過(guò)程
插件服務(wù)稍微復(fù)雜最后再說(shuō)。elasticsearch各個(gè)功能模塊實(shí)現(xiàn)的非常好,解耦非常完美,很多模塊都實(shí)現(xiàn)了生命周期接口,只有啟動(dòng)它才能夠?qū)ν馓峁┓?wù),它的啟動(dòng)過(guò)程也是功能模塊初始化的過(guò)程。因此,node節(jié)點(diǎn)的啟動(dòng)過(guò)程也就是這些模塊初始化的過(guò)程。如下面的代碼片段所示:
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(); } //通過(guò)guice獲取各個(gè)模塊的service接口并啟動(dòng) 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(); …… }
每個(gè)模塊service都會(huì)實(shí)現(xiàn)一個(gè)start接口,模塊功能初始化過(guò)程都是這這個(gè)函數(shù)中實(shí)現(xiàn)。每個(gè)模塊的具體啟動(dòng)過(guò)程后面會(huì)有涉及,這里就不做深入分析。
插件的加載過(guò)程
每個(gè)node在加載各個(gè)模塊前,會(huì)首先加載所需要的插件,如果有些插件加載不成功node會(huì)啟動(dòng)失敗。這里會(huì)加載三類插件:首先是配置插件,配置到節(jié)點(diǎn)配置文件中插件,如分詞插件等;然后查找classpath中能找到的插件,這些插件一般防止在plugin文件夾中;最后是加載site插件,site插件是不涉及java代碼的純網(wǎng)站式插件,如監(jiān)控插件head,bigdesk等。任何使用者都可以開(kāi)發(fā)自己需要的插件,只要按著elasticsearch相關(guān)版本的插件開(kāi)發(fā)規(guī)范來(lái)實(shí)現(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()); } // 檢驗(yàn)代理插件,如果有加載不成功的插件就拋出異常,停止node啟動(dòng)。 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的初始化過(guò)程,在它的初始化過(guò)程中,加載所有能夠找的插件。插件的啟動(dòng)在其他功能模塊之前,些插件,如分詞插件,啟動(dòng)不成功則會(huì)對(duì)節(jié)點(diǎn)的功能造成影響,因此會(huì)在這里就中斷節(jié)點(diǎn)的啟動(dòng)過(guò)程讓用戶知道。這就是節(jié)點(diǎn)的啟動(dòng)過(guò)程。插件加載成功,各個(gè)功能模塊加載并啟動(dòng)成功,節(jié)點(diǎn)就啟動(dòng)成功。
限于篇幅這里模塊相關(guān)詳情都沒(méi)有進(jìn)行深入在接下來(lái)模塊分析中會(huì)一一分析,希望大家以后多多支持腳本之家!
相關(guān)文章
基于Redis分布式鎖Redisson及SpringBoot集成Redisson
這篇文章主要介紹了基于Redis分布式鎖Redisson及SpringBoot集成Redisson,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小小伙伴可以參考一下2022-09-09Java8新特性Stream流中anyMatch和allMatch和noneMatch的區(qū)別解析
這篇文章主要介紹了Java8新特性Stream流中anyMatch和allMatch和noneMatch的區(qū)別解析,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2024-01-01Java實(shí)現(xiàn)批量向mysql寫(xiě)入數(shù)據(jù)的方法
這篇文章主要介紹了Java實(shí)現(xiàn)批量向mysql寫(xiě)入數(shù)據(jù)的方法,涉及java基于JDBC連接mysql數(shù)據(jù)庫(kù)及寫(xiě)入數(shù)據(jù)的相關(guān)操作技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2017-12-12Mybatis插件PageHelper的實(shí)現(xiàn)原理詳解
PageHelper 是一款開(kāi)源的 MyBatis 分頁(yè)插件,可以在實(shí)際應(yīng)用中方便地實(shí)現(xiàn)分頁(yè)功能,這篇文章主要來(lái)和大家講講PageHelper的原理與使用,需要的可以參考下2023-06-06SpringBoot 分布式驗(yàn)證碼登錄方案示例詳解
為了防止驗(yàn)證系統(tǒng)被暴力破解,很多系統(tǒng)都增加了驗(yàn)證碼效驗(yàn),比較常見(jiàn)的就是圖片二維碼,業(yè)內(nèi)比較安全的是短信驗(yàn)證碼,當(dāng)然還有一些拼圖驗(yàn)證碼,加入人工智能的二維碼等等,我們今天的主題就是前后端分離的圖片二維碼登錄方案,感興趣的朋友一起看看吧2023-10-10詳解java中的互斥鎖信號(hào)量和多線程等待機(jī)制
這篇文章主要介紹了Java編程中的互斥鎖,信號(hào)量和多線程等待機(jī)制實(shí)例詳解,簡(jiǎn)單介紹了互斥鎖和信號(hào)量的區(qū)別,需要的朋友可以了解下。2017-09-09java注解之運(yùn)行時(shí)修改字段的注解值操作
這篇文章主要介紹了java注解之運(yùn)行時(shí)修改字段的注解值操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08完全解析Java編程中finally語(yǔ)句的執(zhí)行原理
這篇文章主要深度介紹了Java編程中finally語(yǔ)句的執(zhí)行原理,細(xì)致講解了finally在異常處理中的流程控制作用,需要的朋友可以參考下2015-11-11