本篇爲elasticsearch源碼分析系列文章的第九篇,又到了咱們深扒ElasticSearch源碼的時候了:)java
本篇開始將會詳細解釋Node實例化的過程當中PluginsService的相關內容,PluginService算是Node實例化的重要內容,瞭解PluginService的加載過程有助於咱們理解Node實例化和ElasticSearch啓動時工做流程,此外PluginsService還涉及到ElasticSearch中線程池的使用,關於ElasticSearch中線程池的封裝使用,咱們會在下一篇敘述。服務器
ElasticSearch中的插件是一個容許插入自定義功能的擴展。插件大體分爲三類:app
在ElasticSearch的bin目錄下,能夠執行命令elasticsearch
bin/plugin list:查看已經安裝了的ElasticSearch插件。
bin/plugin install [plugin_name]:安裝一個ElasticSearch插件。
複製代碼
插件的安裝過程如圖所示:函數
在安裝好以後,在ElasticSearch的plugins目錄下就能看到插件包了:工具
能夠看出icu分詞插件是個純java插件。icu 是Elasticsearch的分析器插件,使用國際化組件Unicode(ICU)提供豐富的處理 Unicode編碼的工具。該查件對處理亞洲語言特別有用,還有大量對除英語外其餘語言進行正確匹配和排序所必須的分詞過濾器。源碼分析
落地到編碼層次的話,plugins
文件夾中的插件在Node實例化的時候被加載,構建代碼以下:學習
this.pluginsService = new PluginsService(tmpSettings, environment.configFile(), environment.modulesFile(), environment.pluginsFile(), classpathPlugins);
複製代碼
其中environment.pluginsFile()
的路徑的內容就是xxx\elasticsearch\elasticsearch-6.0.0-rc2\plugins\analysis-icu
。測試
在ElasticSearch的org.elasticsearch.plugins
的包中提供了若干種插件的擴展類,徹底覆蓋了全部插件的擴展需求。除了能實現如下接口:ui
進一步定製ElasticSearch外,除了這個類擴展點還聲明一些@Deprecated
onModule方法。使用這些方法應該特別注意,使用5.x之前風格擴展語法不能成功構建。這也是成功的開源軟件在考慮平滑升級時的設計思路時值得學習的地方。定義了插件的實現方法,這些插件從低版本升級到5.x以後的版本就不會太過艱難。
好比上面提到的icu分詞插件,就實現了AnalysisPlugin, MapperPlugin,這兩個接口。
public class AnalysisICUPlugin extends Plugin implements AnalysisPlugin, MapperPlugin
複製代碼
關於這些插件的詳細解析,咱們會在之後的文章中講解。
通常查看組件源碼都是先從構造函數開始,PluginsService的構造函數爲PluginsService(Settings settings, Path configPath, Path modulesDirectory, Path pluginsDirectory, Collection<Class<? extends Plugin>> classpathPlugins)
。
有以下五個參數,大都是路徑設定類的:
PluginsService先構造了一個List,List的元素爲PluginsInfo類型和Plugin類型的元組(Tuple)。
接着再遍歷classpathPlugins的值中的Plugin實現類對象,經過反射Plugin的實現類,調用方法getConstructors()
獲得Plugin的子類的構造函數,獲得構造函數後,對構造函數進行一系列的檢查:
由此能夠知道,想本身實現ElasticSearch的插件,就必須繼承Plugin類,定義一個構造函數,根據要實現插件的類型實現不一樣的接口,好比SearchPlugin,ScriptPlugin,RepositoryPlugin
。
接下來遍歷modules路徑中各個module的plugin-descriptor.properties
文件,取出文件中的以下屬性:
構造出各個module的PluginInfo對象,而後遍歷出各個module下面的jar包的路徑,這樣每一個module的jar包和信息就都有了,咱們能夠看到ElasticSearch是封裝了一個內部類Bundle,以下圖:
至此找到了全部須要加載的module,下面是加載全部的plugins
首先調用checkForFailedPluginRemovals()
方法,遍歷pluginsDirectory
路徑中全部的包含**.removing-**字符的文件,拋出應該remove該插件的異常IllegalStateException。
檢查完成後,遍歷pluginsDirectory
路徑下的文件,遍歷過程當中,很細心的檢查了當前查詢路徑是不是MacOS或者可能的桌面系統,而不是服務器。若是符合上述條件就跳過該次遍歷,不符合的話依然按照加載module的方法那樣,取得plugins文件夾下的各個plugin的plugin-descriptor.properties
文件,依次加載name,description,version,elasticsearch.version,java.version,has.native.controller,requires.keystore屬性,封裝成PluginInfo,查找出jar包,最後封裝成Bundle對象。
這樣就獲得了兩個Bundle對象,一個modules,一個plugins。構造一個總體集合後,檢查其中的jar包,避免jar-hell。
至此PluginsService對象就已經構造完畢,經過賦值語句this.pluginsService = new PluginsService(tmpSettings, environment.configFile(), environment.modulesFile(), environment.pluginsFile(), classpathPlugins)
,Node就對象得到了PluginsService的對象。
咱們整理一下PluginsService的構造函數作了哪些工做,
在通篇過完了PluginsService類的構造參數後,咱們繼續來看PluginsService對象在Node中起到的做用。
在Node對象構建完了PluginsService對象後,緊接着在Node中,經過PluginsService對象的updatedSettings()
方法,將PluginsService類在構造時從modules和plugins路徑中加載的plugin對象取出遍歷,依次調用各個plugin的additionalSettings()
方法。而後put更新Settings對象,達到了更新Settings對象的目的。
additionalSettings()
這個方法在不一樣的plugin實現類中有不一樣實現,具體做用是構建插件運行過程當中須要的Settings對象。以下圖是Netty4plugin的實現:
因而可知,PluginsService組件中保存的Plugin元組是ElasticSearch發揮功能的重要內容,其中加載的Modules路徑下的Plugin組件一塊兒構成了ElasticSearch的核心主幹功能。
ElasticSearch中線程池的加載參數直接來源於PluginsService,下一篇文章咱們會講解在Node實例化過程當中線程池的封裝過程,但願你們持續關注哦^ _ ^。