本篇为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实例化过程当中线程池的封装过程,但愿你们持续关注哦^ _ ^。