Linux上c++通过JNI调用java代码笔记

最近工作中,需要用到c++通过JNI去访问Java代码,在这里做下自己过程中遇到的问题,做个总结;

1.linux配置java jdk环境

第一步:去官网下载对应的linux包

https://www.oracle.com/java/technologies/javase-jdk11-downloads.html  (这里我用的jdk11)

第二步:解压放在/usr/lib/下面

第三步:配置环境(/etc/profile)

export JAVA_HOME=/usr/lib/jdk-11.0.10
export CLASSPATH=.:${JAVA_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH

这里因为下载的jdk11,因此不存在jre文件夹,不需要单独配置,下面是jdk8版本的配置

export JAVA_HOME=/usr/lib/jdk1.8.0_281
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib/tools.jar:${JAVA_HOME}/lib/dt.jar:${JRE_HOME}/lib/
export PATH=${JAVA_HOME}/bin:${JRE_HOME}/bin:$PATH

配置就完成了,执行source /etc/profile  更新配置,可以进行命令检验一下是否成功

java -version

当打开新的终端出现找不到java command时,请记得执行source /etc/profile,就OK了。

2.c++ 编译过程

第一步:编译java class

javac *.java 编译所有的java文件

javac -cp core-4.1.1.jar:abi-4.1.1.jar:crypto-4.1.1.jar:rlp-4.1.1.jar:utils-4.1.1.jar:tuples-4.1.1.jar  Web3Interface.java  带有第三库的编译

 可能需要的java命令(demo指demo.class)

查看方法签名:javap -classpath ./ -s Demo
查询可执行程序依赖库: ldd 可执行程序
解压jar:jar -xvf project.jar
运行jar:java -jar project.jar
运行java: java demo

第二步:编写c++

流程:

配置jvm参数,初始化JVM

    options[0].optionString = (char*)"-Djava.compiler=NONE";
    options[1].optionString = (char*)"-Djava.class.path=.";
    options[2].optionString = (char*)"-verbose:jni";
    vm_args.version = JNI_VERSION_1_4;
    vm_args.nOptions = 3;
    vm_args.options = options;
    vm_args.ignoreUnrecognized = JNI_TRUE;
    status = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args);

查找对应的类名findclass

获取方法id(构造函数)getmethodid

创建类对象 newObject

获取需要调用的函数方法id getmethodid

调用对象方法


		jclass cls =env->FindClass("project/Web3Interface");
		if(cls == NULL)
		{
			cout<<"find class is null"<<endl;
			return str2jstring("null");
		}
		//Instantiate an object of that class
		jmethodID mid = env->GetMethodID(cls,"<init>","()V"); 
		if(mid == NULL)
		{
			cout<<"find mid is null"<<endl;
			return str2jstring("null");
		} 
		jobject jobj = env->NewObject(cls,mid); 
		 if(jobj == NULL)
		{
			cout<<"find jobj is null"<<endl;
			return str2jstring("null");
		}  
		//get java transfor params
		const char *pdCont = env->GetStringUTFChars(password,JNI_FALSE);
		const char *pathCont = env->GetStringUTFChars(path,JNI_FALSE);
	//	//get method id
		mid = env->GetMethodID(cls,"getdata","(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;");
		if(mid == NULL)
		{
			cout<<"find mid is null"<<endl;
			return str2jstring("null");
		} 
		//call method
		jstring result = (jstring)env->CallObjectMethod(jobj,mid,env->NewStringUTF(pdCont),env->NewStringUTF(pathCont));
		
		return result;

调用jni接口过程中,是需要区分static 和非static的,如果函数是static修饰的则就改为getStaticMethodID()方法,其他类似;

注意事项:

① “-Djava.class.path= ”路径一定要配置正确,不然是找不到class名的;

②多路径时:windows  是;分割,unix 是:分割

例子:
//options[1].optionString = (char*)"-Djava.class.path=.:abi-4.1.1.jar:core-4.1.1.jar";
后面跟的是第三库的jar包路径

 ③java class 路径 要与findclass要匹配

jclass cls =env->FindClass("project/test");    如:  /代替.    如  packet ope.project   ope/project/test

存放class和jar包的路径:c++ 执行程序test   当前 路径下创建project  文件夹(存放java.class和jar)

 

三者需要进行统一才能找得到class,否则找不到;(与“-Djava.class.path”也是一一对应的)

第三步:g++ 编译

 jdk8版本

g++ testjni.cpp -o test -I/usr/lib/jdk1.8.0_281/include/ -I/usr/lib/jdk1.8.0_281/include/linux -I/usr/lib/jdk1.8.0_281/jre/lib/amd64/server/ -L/usr/lib/jdk1.8.0_281/jre/lib/amd64/ -L/usr/lib/jdk1.8.0_281/jre/lib/amd64/server/ -ljvm

jdk11版本

g++ test.cpp main.cpp -o test -I/usr/lib/jdk-11.0.10/include/ -I/usr/lib/jdk1.8.0_281/include/linux -L/usr/lib/jdk-11.0.10/lib/server/ -ljvm

 注意:编译一定要有I/usr/lib/jdk-11.0.10/include/   -I/usr/lib/jdk1.8.0_281/include/linux这俩个路径

编译过程中可能会出现找不到libjvm.so的错误,此时可以通过下面方法去进行配置(/ect/profile添加):

export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:/usr/lib/jdk1.8.0_281/jre/lib/amd64

过程中也许可能会出现找不到libjava.so类似的错误,此时千万不要去复制相应的文件到对应的路径下,这是不行的,解决一个还有另外的,很多.so都要报错,最后全部复制了还不一定能成功;

原因分析:配置的环境的问题或者jdk问题,如果java -version 没有问题,配置也没问题,那么最好的办法就是删除原先的   重新下载  重新配置

 

3.问题

以上对于一个简单的测试demo,c++调用java代码是没有问题的。(不存在第三方库)

但目前遇到一个问题尚未解决,正在解决中:

问题 :运行env->CallObjectMethod(jobj, mid);  会奔溃的

原因:当需要使用第三方库时,java代码执行运行过程中有些库找不到,会出现奔溃的情况,一直未解决(尝试修改路径等),以及通过打包成jar包去调用,尝试了很久,还是未成功,希望大佬可以指导一下;

后面解决了此问题再补到文章后面。

 

如果不需要通过jni方式去调用java代码,可以使用比较笨的方式去实现,利用cmd 或者 system :  java -jar project.jar 命令去拿数据(传参和拿返回数据)。哈哈哈 这是最简单最没技术含量的方式。

 

 

 

 

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值