servlet中Java调用C++,JNI
2016-02-20 15:43
435 查看
servlet中Java调用C++,JNI
阅读:2452013-01-04 10:22标签:杂谈
我想尝试用Java调用旧有的c++代码,在servlet中。这样以前的就代码就可以变成web应用了
其实我研究这个是想以前的应用只要满足了servlet的接口是不是就可以部署到云上,因为Amazon是支持这种部署的,所以想做些试验。
c++是很熟悉了,但是JNI或者Java都不大熟悉。
先要搞出个servlet,我还不太会,所以用的是GWT的模板,这样就有了一个可以debug的servlet。
就这个小事还有点故事,IE总是不能运行,总让我下载GWT的插件,我手动下载并且安装了,但是它还是让我下载。
后来我修改IE的security让activeX可以运行就好了,就有个提示需要手动确认。但是我找了activeX的安装路径并没有发现任何新的ActiveX。
实在是不明白没有安装ActiveX,为啥需要运行ActiveX。可能因为我还不够理解GWT到底是什么。
anyway,我的servlet是有了。
下面就是要创建Java会用的C++程序了。
先在Java中定义这个要在C++里实现的函数的原型
package example.HelloServletAAA.server;
public class NativeCaller {
public native int CallNativeGetInt(int argPlayerID);
static
{
System.out.print('start load!!!');
System.loadLibrary('NativeHelloAAA');
System.out.print('end load!!!');
}
}
这个函数接受一个int返回一个int
然后创建C++的项目,我发现这个c++的项目需要是多字节码的
在c++的头文件中声明要实现的那个函数
#include
#ifndef _Included_APCluster
#define _Included_APCluster
#ifdef __cplusplus
extern 'C' {
#endif
JNIEXPORTjint JNICALL Java_APCluster_CallAPClusterDll
(JNIEnv *, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif
注意前面多的参数,一定是转换过程中需要的
头文件和库文件都从JDk中拿来
然后在cpp中实现刚才声明的函数
#ifdef __cplusplus
extern 'C' {
#endif
JNIEXPORT jint JNICALL Java_APCluster_CallAPClusterDll
(JNIEnv *env, jobject _obj, jint _arg_int)
{
return 59;
}
#ifdef __cplusplus
}
#endif
如果Java代码没有找到想加载的dll会报这个异常java.lang.UnsatisfiedLinkError: no NativeHelloAAA in java.library.path
放在这里依然不好,C:\Users\Administrator\workspace\HelloServletAAA\war\WEB-INF\lib。
最后我把加载路径改成绝对路径就可以了
System.load('C:/Users/Administrator/workspace/HelloServletAAA/war/WEB-INF/lib/NativeHelloAAA.dll');
或者放在这里C:\Program Files\Java\jre6\bin
其实可以放的地方可以查到
System.out.println(System.getProperty('java.library.path'));
得到新的错误
java.lang.UnsatisfiedLinkError: C:\Users\Administrator\workspace\HelloServletAAA\war\WEB-INF\lib\NativeHelloAAA.dll: Can't load IA 32-bit .dll on a AMD 64-bit platform
这是由于我的c++项目设置不对,设置成64的以后就可以加载了
设置成64位的项目要注意设置正确的sub-system和entry point。
SubSystem = Windows (/SUBSYSTEM:WINDOWS)
Entry Point = DllMain
然后接着就是这个错误
Caused by: java.lang.UnsatisfiedLinkError: example.HelloServletAAA.server.NativeCaller.CallNativeGetInt(I)I
这个错误看起来是在指定的dll中找不到方法定义
这个错误的原因就是java和c++两边的签名不吻合
其实有个简单的解决办法,就是用java带的工具生成c++项目用的头文件
workspace\HelloJNICallerAAA\bin>javah -jni NativeCaller
要想用这个命令,要设置java的路径到环境变量中另外java class所在的路径要么也设置成环境变量,要么就当成当前的运行路径才可以
这样生成的头文件类似下面
#include
#ifndef _Included_NativeCaller
#define _Included_NativeCaller
#ifdef __cplusplus
extern 'C' {
#endif
JNIEXPORT jint JNICALL Java_NativeCaller_CallerNativeGetInt
(JNIEnv *, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif
我就发现我的错误了,java中的类要和c++的函数名对应,我以前以为的是java的类是和c++的dll文件名对应,实际上dll文件名在整个调用中不重要,只要能加载就可以了
---------------------------------------------------------------------------------
然后我在我的servlet上试验有遇到了一些困难
servlet的路径要复杂,另外还有包的命名也会增加困难。
最后发现正确的命令是这样
C:\Users\Administrator\workspace\HelloServletAAA\war\WEB-INF\classes>javah -jni -classpath . example.HelloServletAAA.server.NativeCaller
生成的头文件类似这样
#include <jni.h>
#ifndef _Included_example_HelloServletAAA_server_NativeCaller
#define _Included_example_HelloServletAAA_server_NativeCaller
#ifdef __cplusplus
extern 'C' {
#endif
JNIEXPORT jint JNICALL Java_example_HelloServletAAA_server_NativeCaller_CallNativeGetInt
(JNIEnv *, jobject, jint);
#ifdef __cplusplus
}
#endif
#endif
函数的签名反映了包和类的名字
-------------------------------------------------------------------------------------------
怎么debug JNI中的c++项目
很简单,先让java这边停在native的调用之前
然后用c++的编译器attach上去,attach JavaW或者Java的进程就可以了
Switch to Visual Studio, and bring up the 'Attach to process' dialog (Ctrl-Alt-P). Select the java process (javaw.exe or java.exe) by typing 'j'
4加载中...
内容加载失败,点击此处重试
相关文章推荐
- C++语言文件的定义与操作
- 1020. Tree Traversals (25)
- C语言union 关键字与大小端模式
- 【C语言】文件常用读写操作(含读取学生信息示例)
- [UVA1368]DNA Consensus String
- c语言入门之项目2.3——利息计算器
- C++中,什么叫类,结构,联合?
- Unix C++(boost) 线程同步和线程组
- C/C++ 笔试、面试题目大汇总
- 1019. General Palindromic Number (20)
- C++中类的多态与虚函数的使用
- [C++]浅谈构造函数
- 快速排序算法(c++)版
- for循环的条件判断中为什么用'!='而不用'<'
- 如何成为一名高级C++程序员
- C++中自增自减运算符疑惑大全
- C++中new和malloc的区别
- c语言入门之项目2.2——个人所得税计算器
- c++ 设计模式6 (Decorator 装饰模式)
- QT C++实现简单计算器(仿windows计算器普通模式)