文档章节

Elasticsearch学习总结五 elasticSearch插件机制源码解析

winstone
 winstone
发布于 2017/06/02 11:30
字数 1306
阅读 165
收藏 1
el

一.首先看看Elasticsearch中插件是如何安装的

我们安装好es后,如果要安装插件需要在 /usr/local/elasticsearch/bin的目录下使用plugin这个shell脚本,仔细看了下这个shell脚本,发现里面主要是运行了org.elasticsearch.plugins.PluginManager这个类 exec "$JAVA" $JAVA_OPTS $ES_JAVA_OPTS -Xmx64m -Xms16m -Delasticsearch -Des.path.home="$ES_HOME" $properties -cp "$ES_HOME/lib/*" org.elasticsearch.plugins.PluginManager $args

下面我们进入PluginManager这个类中看看是如何下载安装插件的,如何执行这个类,肯定应该有个main方法吧,果真如此,下面是pluginManager的main方法

public static void main(String[] args) {
       ..........
        String url = null;
        OutputMode outputMode = OutputMode.DEFAULT;
        String pluginName = null;
        TimeValue timeout = DEFAULT_TIMEOUT;
        int action = ACTION.NONE;
        if (args.length < 1) {
            displayHelp(null);
        }
        try {
            for (int c = 0; c < args.length; c++) {
                String command = args[c];
                switch (command) {
                    case "-u":
                    case "--url":
                    // deprecated versions:
                    case "url":
                    case "-url":
                        url = getCommandValue(args, ++c, "--url");
                        // Until update is supported, then supplying a URL implies installing
                        // By specifying this action, we also avoid silently failing without
                        //  dubious checks.
                        action = ACTION.INSTALL;
                        break;
                    case "-v":
                    case "--verbose":
                    // deprecated versions:
                    case "verbose":
                    case "-verbose":
                        outputMode = OutputMode.VERBOSE;
                        break;
                    case "-s":
                    case "--silent":
                    // deprecated versions:
                    case "silent":
                    case "-silent":
                        outputMode = OutputMode.SILENT;
                        break;
                    case "-i":
                    case "--install":
                    // deprecated versions:
                    case "install":
                    case "-install":
                        pluginName = getCommandValue(args, ++c, "--install");
                        action = ACTION.INSTALL;
                        break;
                    case "-r":
                    case "--remove":
                    // deprecated versions:
                    case "remove":
                    case "-remove":
                        pluginName = getCommandValue(args, ++c, "--remove");
                        action = ACTION.REMOVE;
                        break;
                    case "-t":
                    case "--timeout":
                    // deprecated versions:
                    case "timeout":
                    case "-timeout":
                        String timeoutValue = getCommandValue(args, ++c, "--timeout");
                        timeout = TimeValue.parseTimeValue(timeoutValue, DEFAULT_TIMEOUT);
                        break;
                    case "-l":
                    case "--list":
                        action = ACTION.LIST;
                        break;
                    case "-h":
                    case "--help":
                        displayHelp(null);
                        break;
                    default:
                        displayHelp("Command [" + command + "] unknown.");
                        // Unknown command. We break...
                        System.exit(EXIT_CODE_CMD_USAGE);
                }
            }
        } catch (Throwable e) {
            displayHelp("Error while parsing options: " + e.getClass().getSimpleName() +
                    ": " + e.getMessage());
            System.exit(EXIT_CODE_CMD_USAGE);
        }

上面代码中,就是当你输入各种命令的时候,pluginManager都会根据响应的命令触发不同的动作,例如输入./plugin list 就会显示当前es安装了那些插件

输入图片说明

当输入 plugin -install mobz/elasticsearch-head 命令的时候,pluginManager就会去获取当前插件名称, pluginName = getCommandValue(args, ++c, "--install"); 并且将 action赋值 action = ACTION.INSTALL; 当完成赋值后会继续执行如下代码,这部分代码主要构造PluginManger对象,并且根据action的动作去执行相应的操作,pluginManager.downloadAndExtract(pluginName);会根据插件名称去下载相应的插件

................
 if (action > ACTION.NONE) {
            int exitCode = EXIT_CODE_ERROR; // we fail unless it's reset
            //构造pluginManger
            PluginManager pluginManager = new PluginManager(initialSettings.v2(), url, outputMode, timeout);
            switch (action) {
                case ACTION.INSTALL:
                    try {
                        pluginManager.log("-> Installing " + Strings.nullToEmpty(pluginName) + "...");
                        pluginManager.downloadAndExtract(pluginName);//执行下载解压任务
                        exitCode = EXIT_CODE_OK;
                    } catch (IOException e) {
                        exitCode = EXIT_CODE_IO_ERROR;
                        pluginManager.log("Failed to install " + pluginName + ", reason: " + e.getMessage());
                    } catch (Throwable e) {
                        exitCode = EXIT_CODE_ERROR;
                        displayHelp("Error while installing plugin, reason: " + e.getClass().getSimpleName() +
                                ": " + e.getMessage());
                    }
                    break;
.........................

PluginManager的构造函数主要是传入下载地址,延时时长等,下面看下downloadAndExtract下载安装是如何工作的

 public void downloadAndExtract(String name) throws IOException {
        .....
        HttpDownloadHelper downloadHelper = new HttpDownloadHelper();
        boolean downloaded = false;
        HttpDownloadHelper.DownloadProgress progress;
        if (outputMode == OutputMode.SILENT) {
            progress = new HttpDownloadHelper.NullProgress();
        } else {
            progress = new HttpDownloadHelper.VerboseProgress(System.out);
        }
         .........
        if (url != null) {
            URL pluginUrl = new URL(url);
            log("Trying " + pluginUrl.toExternalForm() + "...");
            try {
                downloaded = true;
                downloadHelper.download(pluginUrl, pluginFile, progress, this.timeout);
            } catch (ElasticsearchTimeoutException e) {
                throw e;
            } catch (Exception e) {
                // ignore
                log("Failed: " + ExceptionsHelper.detailedMessage(e));
            }
        }

主要是通过构建HttpDownloadHelper 实现http下载,并且实现了一个下载进度器,这就是我们安装插件的时候会有一些输出的原因,通过downloadHelper.download(pluginUrl, pluginFile, progress, this.timeout);可以真正的实现下载,这里就不在赘述了,当下载完毕后,会去执行解压和安装的过程,在解压文件时候越过父文件夹,将文件解压到指定目录,比如head文件夹中,至此下载安装基本完毕


   ZipFile zipFile = null;
        try {
            zipFile = new ZipFile(pluginFile);
            boolean removeTopLevelDir = topLevelDirInExcess(zipFile);
            Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();
            while (zipEntries.hasMoreElements()) {
                ZipEntry zipEntry = zipEntries.nextElement();
                if (zipEntry.isDirectory()) {
                    continue;
                }
                String zipEntryName = zipEntry.getName().replace('\\', '/');
                if (removeTopLevelDir) {
                    zipEntryName = zipEntryName.substring(zipEntryName.indexOf('/'));
                }
                File target = new File(extractLocation, zipEntryName);
                FileSystemUtils.mkdirs(target.getParentFile());
                Streams.copy(zipFile.getInputStream(zipEntry), new FileOutputStream(target));
            }
            log("Installed " + name + " into " + extractLocation.getAbsolutePath());
        } catch (Exception e) {
            log("failed to extract plugin [" + pluginFile + "]: " + ExceptionsHelper.detailedMessage(e));
            return;
        } finally {
            if (zipFile != null) {
                try {
                    zipFile.close();
                } catch (IOException e) {
                    // ignore
                }
            }
            pluginFile.delete();
        }

二. elasticSearch是如何加载插件的

elasticsearch里面的组件基本都是用上面的方式进行模块化管理,elasticsearch对guice进行了简单的封装,通过ModulesBuilder类构建es的模块,一个es节点肯定够包括PluginsModule插件模块,下面我们看下插件模块是如何工作,加载我们的插件的

public class PluginsModule extends AbstractModule implements SpawnModules, PreProcessModule {

    private final Settings settings;

    private final PluginsService pluginsService;

    public PluginsModule(Settings settings, PluginsService pluginsService) {
        this.settings = settings;
        this.pluginsService = pluginsService;
    }

    //预处理组件 
    public Iterable<? extends Module> spawnModules() {
        List<Module> modules = Lists.newArrayList();
        Collection<Class<? extends Module>> modulesClasses = pluginsService.modules();
        for (Class<? extends Module> moduleClass : modulesClasses) {
            modules.add(createModule(moduleClass, settings));
        }
        modules.addAll(pluginsService.modules(settings));
        return modules;
    }
..............

es中所有的组件都是继承自AbstractModule 插件调用层次为Modules->PluginsModule->PluginsService->XXPlugin; 都是调用void processModule(Module module)方法。 区别在于 1:PluginsModule实现的是PreProcessModule接口。 2:PluginsService是自己本来的方法。 3:XXPlugin实现的是Plugin接口。 虽然他们都有processModule方法,但不是实现的同一个类。最重要是的还是pluginService类,它真正负责加载的插件类

 public PluginsService(Settings settings, Environment environment) {
        super(settings);
        this.environment = environment;
        this.checkLucene = componentSettings.getAsBoolean("check_lucene", true);
       .................................忽律部分代码
        loadPluginsIntoClassLoader();
        if (loadClasspathPlugins) {
            tupleBuilder.addAll(loadPluginsFromClasspath(settings));
        }
        this.plugins = tupleBuilder.build();

      // we load site plugins
        ImmutableList<Tuple<PluginInfo, Plugin>> tuples = loadSitePlugins();
        for (Tuple<PluginInfo, Plugin> tuple : tuples) {
            sitePlugins.add(tuple.v1().getName());
        }
      .................................忽律部分代码

其中loadPluginsIntoClassLoader();负责classloader加载class,加载不在当前classpath中的class,使用当前setting中的classloader,这个构造函数负责加载plugin下面的所有的插件,并且使用当前的类加载器加载。

至此,插件的下载和加载全部完成。

© 著作权归作者所有

winstone
粉丝 38
博文 14
码字总数 17575
作品 0
南京
程序员
私信 提问
渣渣菜鸡为什么要看 ElasticSearch 源码?

前提 人工智能、大数据快速发展的今天,对于 TB 甚至 PB 级大数据的快速检索已然成为刚需,大型企业早已淹没在系统生成的浩瀚数据流当中。大数据技术业已集中在如何存储和处理这些海量的数据...

Java小铺
2018/08/10
119
0
渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(下)

关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/12/es-code03/ 前提 上篇文章写完了 ES 流程启动的一部分,main 方法都入口,以及创建 Elasticsearch 运行的必须环...

zhisheng_tian
2018/08/14
0
0
ES(elasticsearch)搜索引擎

ES(elasticsearch)搜索引擎 0、授人以渔,少走半年弯路! 死磕 Elasticsearch 方法论:普通程序员高效精进的 10 大狠招! 一、Elasitcsearch基础篇 1.1 Elasitcsearch基础认知 1、Elasticse...

Ocean_K
2018/09/11
1K
6
bboss elasticsearch v5.0.3.9.5 发布

bboss elasticsearch v5.0.3.9.5发布。 bboss elasticsearch特性 bboss es是一个不错的elasticsearch java客户端、高性能Elasticsearch ORM开发库。bboss es类似于mybatis,使用xml文件管理e...

bboss
2018/03/02
681
1
elasticsearch搜索引擎相关资料(更新中)

最近需要用到elasticsearch搜索引擎,所以搜集了很多相关资料,先放在这里(未详细整理) 一、步骤总结:(linux环境下) 1. 安装 (1)下载elasticsearch安装包:http://www.elasticsearch....

核桃人
2018/03/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

好程序员大数据学习路线分享函数+map映射+元祖

好程序员大数据学习路线分享函数+map映射+元祖,大数据各个平台上的语言实现 hadoop 由java实现,2003年至今,三大块:数据处理,数据存储,数据计算 存储: hbase --> 数据成表 处理: hive --> 数...

好程序员官方
今天
6
0
tabel 中含有复选框的列 数据理解

1、el-ui中实现某一列为复选框 实现多选非常简单: 手动添加一个el-table-column,设type属性为selction即可; 2、@selection-change事件:选项发生勾选状态变化时触发该事件 <el-table @sel...

everthing
今天
6
0
【技术分享】TestFlight测试的流程文档

上架基本需求资料 1、苹果开发者账号(如还没账号先申请-苹果开发者账号申请教程) 2、开发好的APP 通过本篇教程,可以学习到ios证书申请和打包ipa上传到appstoreconnect.apple.com进行TestF...

qtb999
今天
10
0
再见 Spring Boot 1.X,Spring Boot 2.X 走向舞台中心

2019年8月6日,Spring 官方在其博客宣布,Spring Boot 1.x 停止维护,Spring Boot 1.x 生命周期正式结束。 其实早在2018年7月30号,Spring 官方就已经在博客进行过预告,Spring Boot 1.X 将维...

Java技术剑
今天
17
0
浅谈java过滤器Filter

一、简介 Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码、做一些业务逻辑判断如是否有权限访问页面等。其工作原理是,只要你在web.xml...

青衣霓裳
今天
9
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部