Java调用elasticsearch本地代码的操作方法

Java调用elasticsearch本地代码的操作方法

虽然java虚拟机为开发人员屏蔽了底层的实现细节,使得开发人员不用考虑底层操作系统的差异性。不过在某些应用程序中,还是免不了要直接与底层操作系统上的原生代码进行交互。今天我们就来看一下Java对本地调用提供的支持。

一、为什么要进行本地调用

1.基于性能的考虑

Java语言从其运行速度上来说,在大多数方面是慢于底层操作系统上原生的C和C++等语言的。这主要是由于Java虚拟机这个中间层次的存在。如果完全用Java语言实现的性能无法达到程序的预期要求,可以选择把部分重要且耗时的代码用C或C++来实现。

2.基于某些特殊的需求

Java平台提供的标准类库的功能很强大,包括了在开发中可能遇到的大部分功能。但是仍然有一些功能无法用标准API来实现,主要是一些与底层硬件平台直接交互的功能。Java虚拟机没有把这一部分功能暴露给运行在其上的程序。如果需要这方面的功能,那么只能使用原生代码来进行开发。

3.与已有的使用原生代码编写的程序之间进行集成。

如果Java程序需要与底层操作系统上由C和C++语言开发的程序进行交互,那么可以进行本地调用。

我们平时的开发更多的情况是后边两种情况;在elasticsearch中基本上是属于第二种情况。

二、使用JNI实现本地调用

针对以上提到的各种情况,Java提供了JNI(Java Native Interface)和JNA(Java Native Access)两种方式,其中JNI的一个重要使用场景是提高程序的性能。当对程序中关键部分的性能要求比较高的时候,可以使用C和C++代码来实现。

我们先来看下怎么使用JNI来进行本地调用。

首先我们需要有一个Java类来声明本地方法,并负责加载本地代码库。本地方法与Java接口中的方法或抽象类中的抽象方法一样,只包含方法声明,没有相关的实现。程序中的其他部分可以用正常的方法调用本地方法,比如参数传递和返回值使用等都与正常的方法相同。当虚拟机在执行本地方法时,会尝试在已经加载的本地代码库中查找本地方法的对应实现。在查找到对应的实现方法之后,虚拟机会负责进行参数传递、实际方法调用和返回值传递等工作。

public class HelloNative {

static{

    System.loadLibrary("greetLib");

}

public static native  void greeting();

}

下一步要编写实现本地方法的C/C++代码。Java提供的命令行工具根据Java源代码生成C/C++代码所需的头文件。对于本地方法,头文件中会包含相关的方法声明与其对应。

F:\source\JNI\src>javac -h .\ .\HelloNative.java

通过下边自动生成的头文件,我们可以看到这里有很多的隐式约定,我们只要按照这个声明进行实现即可,具体的规则不是今天的重点,不进行详述。

#include

#ifndef _Included_HelloNative

#define _Included_HelloNative

#ifdef __cplusplus

extern “C” {

#endif

JNIEXPORT void JNICALL Java_HelloNative_greeting

(JNIEnv *, jclass);

#ifdef __cplusplus

}

#endif

#endif

三、elasticsearch使用JNA实现本地调用

通过上边对JNI的简单了解,我们更多的时候碰到的情况是,在编写Java程序之前,就已经有了可以使用的本地代码库。这个本地代码库可能是程序的一部分,也可能是底层操作系统自带的。这些本地代码库的特点是在实现的时候并没有考虑与Java虚拟机的集成,因此也没有使用与JNI相关的内容。在使用这样的本地代码库时,我们就需要一个中间的本地代码库作为桥梁。这个本地代码库作为Java程序中本地方法的实现,负责实际调用时的参数类型转换和返回值传递等工作。这个过程是十分的繁琐的,Java提供了JNA来支持这种情况。

我们知道elasticsearch启动的时候需要检测当前用户是否是root用户,这个检测是直接调用的底层操作系统的代码,我们来看下elasticsearch是怎样使用JNA实现的。

首先elasticsearch提供了Natives类,作为调用本地方法的入口,并负责检测JNA的可用性。

static {

    boolean v RJBTyk=false;

    try {

        // load one of the main JNA classes to see if the classes areRJBTyk available. this does not ensure that all native

        // libraries are available, only the ones necessary by JNA to function

        Class.forName("com.sun.jna.Native");

        v=true;

    } catch (ClassNotFoundException e) {

        logger.warn("JNA not found. native methods will be disabled.", e);

    } catch (UnsatisfiedLinkError e) {

        logger.warn("unable to load JNA native support library, native methods will be disabled.", e);

    }

    JNA_AVAILABLE=v;

}

检测JNA是否可用,然后再调用JNANatives的对用方法

static boolean definitelyRunningAsRoot() {

    if (!JNA_AVAILABLE) {

        logger.warn("cannot check if running as root because JNA is not available");

        return false;

    }

    return JNANatives.definitelyRunningAsRoot();

}

在JNANatives的definitelyRunningAsRoot中,如果是非windows系统,则调用

JNACLibrary.geteuid

static boolean definitelyRunningAsRoot() {

    if (Constants.WINDOWS) {

        return false; // don't know

    }

    try {

        return JNACLibrary.geteuid()==0;

    } catch (UnsatisfiedLinkError e) {

        // this will have already been logged by Kernel32Library, no need to repeat it

        return false;

    }

}

elasticsearch使用JNAKernel32Library来封装对windows的Kernel32的调用,使用 JNACLibrary来封装对非windows系统的libc的调用

static {

    try {

        Native.register("c");

    } catch (UnsatisfiedLinkError e) {

        logger.warn("unable to link C library. native methods (mlockall) will be disabled.", e);

    }

}

static native int mlockall(int flags);

static native int geteuid();

四、总结

JNI更适合使用本地调用来解决对性能有更高要求的场景,需要我们自己使用C或者C++来实现处理逻辑。对于调用已有的本地库的方法或者操作系统的方法,使用JNA更为方便便捷。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是 Elasticsearch Java API 中 UpdateAliases 方法调用示例: ```java import org.elasticsearch.action.admin.indices.alias.Alias; import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; public class UpdateAliasesExample { public static void main(String[] args) throws IOException { // 创建 Elasticsearch 客户端 RestHighLevelClient client = RestClientUtil.createHighLevelClient(); // 创建 IndicesAliasesRequest 请求 IndicesAliasesRequest request = new IndicesAliasesRequest(); // 创建别名操作 Alias addAlias = new Alias("my_alias"); Alias removeAlias = new Alias("old_alias").removeIndex("old_index"); // 创建 XContentBuilder XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject(); { // 添加别名操作 builder.startObject("actions"); { builder.startObject("add"); { builder.startObject(addAlias.name()); { builder.field("index", "my_index"); builder.field("alias", "my_alias"); } builder.endObject(); } builder.endObject(); } builder.endObject(); // 删除别名操作 builder.startObject("actions"); { builder.startObject("remove"); { builder.startObject(removeAlias.name()); { builder.field("index", removeAlias.indices()[0]); builder.field("alias", removeAlias.getAlias()); } builder.endObject(); } builder.endObject(); } builder.endObject(); } builder.endObject(); // 将 XContentBuilder 转换成 String String jsonString = builder.prettyPrint().string(); // 将请求添加到 IndicesAliasesRequest 中 request.source(jsonString, XContentType.JSON); // 发送请求 client.indices().updateAliases(request, RequestOptions.DEFAULT); // 关闭客户端 client.close(); } } ``` 在上面的示例中,我们使用 `IndicesAliasesRequest` 对象创建了一个别名操作,包括添加别名和删除别名。我们使用 `XContentBuilder` 创建了一个 JSON 请求体,将别名操作添加到 `actions` 中,并将其添加到 `IndicesAliasesRequest` 请求中。最后,我们使用 `RestHighLevelClient` 发送请求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值