Elasticsearch 2.X 版本Java插件开发简述
1:elasticsearch插件分类简述
2:Java插件开发要点
3:如何针对不同版本elasticsearch提供多版本的插件
4:插件具有外部依赖时遇到的一些问题(2016-09-07更新)
elasticsearch插件分类简述
elasticsearch插件分为Site插件及Java插件,前者比如使用最广泛的head插件,而后者比如elastic官方提供的商业插件shield。
需要注意的是Site插件从elasticsearch2.3.0版本开始已被标记为Deprecated,并将从5.0.0版本开始被正式移除,相关的Site插件将被整合到kibana中,或者单独部署web server。具体如何整合我还不太清楚。
下文主要记录Java插件的开发要点,以maven管理为例。
Java插件开发要点
以下一一个简单功能为例来说明开发流程,该插件记录所有对部署elasticsearch节点的请求,并且根据指定的配置参数,过滤掉敏感操作(DELETE)
1:Java插件入口
继承org.elasticsearch.plugins.Plugin类的入口类,并实现onModule方法。该类中可以通过settings访问elasticsearch配置文件,获取配置信息,并加载下一步的handler,具体实现代码如下所示:
package org.elasticsearch.es.plugin;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestModule;
import org.elasticsearch.plugins.Plugin;
@SuppressWarnings("static-method")
public class MyRestPlugin extends Plugin {
private final Settings settings;
public MyRestPlugin(Settings settings){
this.settings = settings;
}
@Override
public String name(){
return "MyRest";
}
@Override
public String description(){
return "ElasticSearch Plugin";
}
public void onModule(RestModule module){
String isPluginEnabled = settings.get("ld.enabled");
MethodAuthenticator.setEnabledStr(isPluginEnabled);
if(isPluginEnabled != null && isPluginEnabled.toLowerCase().equals("true")){
MethodAuthenticator.setIsPluginEnabled(true);
String[] denyMethods = settings.getAsArray("ld.deny", new String[]{});
if(denyMethods != null){
MethodAuthenticator.setDenyMethods(denyMethods);
}
} else {
MethodAuthenticator.setIsPluginEnabled(false);
}
module.addRestAction(MyRestHandler.class);
}
}
配置文件信息放入authenticator静态类,代码如下:
package org.elasticsearch.es.plugin;
import java.util.Arrays;
public class MethodAuthenticator{
private static String enabledStr;
private static boolean isPluginEnabled;
private static String[] denyMethods;
// public MethodAuthenticator(){
//
// }
public static boolean isMethodEnabled(String method){
if(denyMethods == null) {
MyLogger.debug("The deny methods is null");
return true;
}
if(Arrays.asList(denyMethods).contains(method)){
return false;
} else {
return true;
}
}
public static String getEnabledStr(){
return enabledStr;
}
public static void setEnabledStr(String enabledStr){
MethodAuthenticator.enabledStr = enabledStr;
}
public static boolean getIsPluginEnabled() {
return isPluginEnabled;
}
public static String[] getDenyMethods() {
return denyMethods;
}
public static void setIsPluginEnabled(boolean isPluginEnabled) {
MethodAuthenticator.isPluginEnabled = isPluginEnabled;
}
public static void setDenyMethods(String[] denyMethods) {
MethodAuthenticator.denyMethods = denyMethods;
}
}
2:相关的Handler
继承org.elasticsearch.rest.BaseRestHandler类的handler,将filter注入controller,实现代码如下:
package org.elasticsearch.es.plugin;
import org.elasticsearch.rest.*;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
public class MyRestHandler extends BaseRestHandler {
@Inject
public MyRestHandler(Settings settings, RestController restController, Client client){
super(settings, restController, client);
RestFilter filter = new MyRestFilter(client);
restController.registerFilter(filter);
}
@Override
protected void handleRequest(RestRequest restRequest, RestChannel restChannel, Client client)
throws Exception {
// TODO Auto-generated method stub
}
}
3:注入Filter
继承org.elasticsearch.rest.RestFilter类的filter,在过滤器中实现对请求的记录及过滤,实现代码如下:
package org.elasticsearch.es.plugin;
import org.elasticsearch.client.Client;
import org.elasticsearch.rest.RestFilter;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestChannel;
import org.elasticsearch.rest.RestFilterChain;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.BytesRestResponse;
import java.net.InetSocketAddress;
public class MyRestFilter extends RestFilter{
Client client;
public MyRestFilter(Client client){
this.client = client;
}
@Override
public void process(RestRequest request, RestChannel channel, RestFilterChain filterChain) throws Exception{
try{
if(MethodAuthenticator.getIsPluginEnabled()){
MyLogger.info(getLogInfo(request));
String methodStr = request.method().name().toLowerCase();
if(MethodAuthenticator.isMethodEnabled(methodStr)){
//MyLogger.info("The request method " + methodStr + " is allowed");
filterChain.continueProcessing(request, channel);
} else {
MyLogger.info("The request method " + methodStr + " is denyed");
BytesRestResponse res = new BytesRestResponse(RestStatus.FORBIDDEN, "Forbidden Method Request by MyRest plugin");
channel.sendResponse(res);
}
} else {
//MyLogger.info("MyRest is disabled");
filterChain.continueProcessing(request, channel);
}
} catch (Exception exp) {
channel.sendResponse(new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, "My Rest Filter internal exception"));
}
return ;
}
private String getLogInfo(RestRequest request) throws Exception {
try{
String pathStr = request.path();
String ipaddr = ((InetSocketAddress)request.getRemoteAddress()).getAddress().getHostAddress();
return "The [" + request.method().name() + "] request [" + pathStr + "] is from [" + ipaddr + "]";
} catch (Exception exp) {
MyLogger.error("Request resolve failed: ", exp);
}
return "The request resolve failed";
}
}
日志记录使用elasticsearch的logger,入口static类代码如下所示:
package org.elasticsearch.es.plugin;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
public class MyLogger {
private static ESLogger esLogger;
static {
esLogger = ESLoggerFactory.getLogger("myRest");
}
public static void debug(String msg){
esLogger.debug(msg);
}
public static void info(String msg){
esLogger.info(msg);
}
public static void warn(String msg){
esLogger.warn(msg);
}
public static void error(String msg){
esLogger.error(msg);
}
public static void error(String msg, Exception exp){
esLogger.error(msg, exp);
}
}
4:插件配置信息
由于插件使用elasticsearch配置文件保存配置信息,因此在配置文件中加入如下信息:
默认elasticsearch配置文件路径为:/etc/elasticsearch/elasticsearch.yml
ld.enabled: false ld.deny: ["delete"]
需要注意的是配置文件中配置项前面加入2个空格字符,否则可能导致elasticsearch不能启动;
此外,插件正常工作还依赖于plugin-descriptor.properties文件(elasticsearch-1.x版本中是es-plugin.properties文件),该文件配置信息如下例:
name=myRest description=GridsumLawDissectorElasticSearchPlugin version=0.0.1 jvm=true site=false classname=org.elasticsearch.es.plugin.MyRestPlugin java.version=1.8 elasticsearch.version=2.3.3
我这里以elasticsearch-2.3.3版本为例,可按需求改为2.X的任意版本。
插件描述文件如下所示(其中format指定插件以zip形式安装):
<?xml version="1.0" encoding="UTF-8"?>
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>plugin</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<useTransitiveFiltering>true</useTransitiveFiltering>
</dependencySet>
</dependencySets>
</assembly>
5:编译部署
插件编译使用maven即可:
mvn clean package
需要注意的是如果首次编译可能需要较长时间,maven会下载目标版本的org.elasticsearch.jar。
版本信息在maven对应的pom文件中指定。
编译完成后,将打包的jar文件与plugin-descriptor.properties文件打包为zip安装包,拷贝至elasticsearch的部署节点。
使用如下方式安装插件:
/usr/share/elasticsearch/bin/plugin install file:///opt/myrest.zip
指令中需要说明的是:
1)elasticsearch安装目录下的bin目录下的plugin脚本;
2)由于直接通过打包安装文件安装,因此指定为file://;
3)紧跟打包zip文件的路径即可。
部署完毕后,确保elasticsearch.yml中的配置信息正确,即可重启elasticsearch节点:
systemctl restart elasticsearch
6:验证插件
通过监控elasticsearch日志可看到插件记录的所有请求目标及来源:
tail -f /var/log/elasticsearch/xx.xx.log
上述命令中为log的默认路径,查看以集群clustername命名的日志文件即可。
如果配置参数中过滤方法设置了DELETE,则可通过发送DELETE请求来验证,插件将过滤该请求,并返回403。
如何针对不同版本elasticsearch提供多版本的插件
如前文所述,elasticsearch从2.X版本开始JAVA插件相关的Plugin,BaseRestHandler,RestFilter等抽象类都相同,区别只在于依赖的org.elasticsearch,因此,JAVA插件对elasticsearch2.X以上各版本的支持,只需要修改对应的依赖版本信息并重新打包部署即可。
具体的两个需要修改依赖版本信息的文件分别是:
plugin-descriptor.properties pom.xml
当然这是以maven为例,如果不是以maven,则只需修改第一个文件的版本信息,并手动引用对应版本的org.elasticsearch,重新编译打包即可。
插件具有外部依赖时遇到的一些问题(2016-09-07更新)
最近由于插件功能扩展,需要用到json序列化,使用了fastJson的1.2.16版本,如下是dependency:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version></version>
</dependency>
遇到的问题主要是在插件部署环节,主要有2个问题:
1:插件发布并未包含依赖的jar包;
2:fastJson.jar需要许可权(不知道表述是否正确,本人不是javaer),以下为问题2的异常信息:
java.security.AccessControlException: access denied (java.lang.RuntimePermission getClassLoader) ... ... ...略
解决方法:
1:在插件发布后打包zip过程中加入fastjson-1.2.16.jar即可,如果打包的package中未包含该jar包,可以从maven的repository路径中获取;
2:更改java.policy文件许可权(默认路径/usr/java/jdk1.8.0_73/jre/lib/security/java.policy),jdk版本为目标主机的jdk版本,在grant中加入以下许可信息:
permission java.lang.RuntimePermission "createClassLoader"; permission java.lang.RuntimePermission "getClassLoader";
重启elasticsearch进程即可。
java.policy如找不到,可以在/usr/lib/jvm/java-1.8.0/jre/lib/security路径下找到。
Elasticsearch 2.X 版本Java插件开发简述的更多相关文章
- Elasticsearch 1.X 版本Java插件开发
接上一篇<Elasticsearch 2.X 版本Java插件开发简述> 开发1.X版本elasticsearch java插件与2.X版本有一些不同,同时在安装部署上也有些不同,主要区别 ...
- Java版本及历史简述
Java版本及历史简述 初学Java,对于Java那么多版本很困惑,这里做一点笔记,如有错误希望指出. Java由Sun公司创造,后Sun公司被Oracle公司收购,Java也随之变为Oracle的产 ...
- elasticsearch源码分析及插件开发
ElasticSearch是一个基于Lucene的搜索服务器.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口.Elasticsearch是用Java开发的,并作为Apach ...
- SpringBoot整合ElasticSearch实现多版本的兼容
前言 在上一篇学习SpringBoot中,整合了Mybatis.Druid和PageHelper并实现了多数据源的操作.本篇主要是介绍和使用目前最火的搜索引擎ElastiSearch,并和Spring ...
- Elasticsearch教程(二)java集成Elasticsearch
1.添加maven <!--tika抽取文件内容 --> <dependency> <groupId>org.apache.tika</groupId> ...
- Elasticsearch 6.x版本全文检索学习之分布式特性介绍
1.Elasticsearch 6.x版本全文检索学习之分布式特性介绍. 1).Elasticsearch支持集群默认,是一个分布式系统,其好处主要有两个. a.增大系统容量,如内存.磁盘.使得es集 ...
- Elasticsearch 6.x版本全文检索学习之Search API
Elasticsearch 6.x版本全文检索学习之Search API. 1).Search API,实现对es中存储的数据进行查询分析,endpoind为_search,如下所示. 方式一.GET ...
- 微信机器人 返现机器人 pc版本 移动版本 java开发 小范省钱
微信机器人 返现机器人 pc版本 移动版本 java开发 小范省钱 微信搜索微信号 fanli-x 或 扫描下方二维码,可查看效果. 非web版微信,pc/移动版微信 支持新号24小时 不封号! 有任 ...
- 下载各个版本java (Java Development Kit)
本文介绍怎么样下载各个版本java开发工具包. 方法/步骤 打开官方下载网址:http://www.oracle.com/technetwork/java/javase/downloads/ind ...
随机推荐
- java 28 - 2 设计模式之 模版设计模式
模版设计模式 模版设计模式概述 模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现 优点 使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求 ...
- poj1573 Robot Motion
Robot Motion Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 12507 Accepted: 6070 Des ...
- Android中使用Gson解析JSON数据的两种方法
Json是一种类似于XML的通用数据交换格式,具有比XML更高的传输效率;本文将介绍两种方法解析JSON数据,需要的朋友可以参考下 Json是一种类似于XML的通用数据交换格式,具有比XML更高的 ...
- virtual box使用
1.工具栏菜单显示 用的是mac电脑.开始发现分辨率小,选了视图->全屏模式的菜单之后发现工具栏菜单不见了. 解决办法:用一个外置键盘,右ctrl+c进行恢复 virtualBox菜单栏和状态栏 ...
- 对于大量left join 的表查询,可以在关键的 连接节点字段上创建索引。
对于大量left join 的表查询,可以在关键的 连接节点字段上创建索引. 问题: 大量的left join 怎么优化 select a.id,a.num,b.num,b.pcs,c.num, c. ...
- browserify使用手册
简介 这篇文档用以说明如何使用browserify来构建模块化应用 browserify是一个编译工具,通过它可以在浏览器环境下像nodejs一样使用遵循commonjs规范的模块化编程. 你可以使用 ...
- 截取视图某一段另存为部分视图(Partial View)
在做ASP.NET MVC后台管理程序时,根据程序需要,Isus.NET需要实现一个功能,就是动态截取视图某一段另存为部分视图Partial View. 思路为在视图中,使用jQury的程序截图以及P ...
- Easyui Tree方法扩展 - getLevel(获取节点级别)
Easyui Tree一直就没有提供这个方法,以前没有用到,所以一直没怎么在意,这次自己用到了,顺便扩展了一个方法,分享给大家. $.extend($.fn.tree.methods, { getLe ...
- DocOptimizer 0.9.0 Beta Released
DocOptimizer 是一个文档优化工具,它通过移除Excel中多余的单元格:将嵌入的OLE替换成图片:移除文档中的隐藏信息:优化文档中的图片等等手段,将Office或PDF文件压缩20%-90% ...
- 代码整洁--使用CodeMaid自动程序排版
在项目开发的过程中,如果只是验证命名规则.而没有统一程序排版,项目中很容易就会出现类似下列范例的程序代码产出.这样的产出,虽然能够正常地提供项目功能.并且符合微软的命名规则,但是因为程序排版凌乱的问题 ...