Java EJB到JNI(C+;+;)调用
我正在尝试使用JNI从EJB调用windows上的本机库(dll)。我读过很多博客,网站建议EJB规范中不允许从EJB进行JNI调用。不过也有特定于供应商的例外情况。我使用weblogic作为EJB容器。如果你能在这方面给我提供指导/建议。我知道资源适配器是一种选择,但对于简单的需求来说,实现它是一项艰巨的任务。这是我的方法Java EJB到JNI(C+;+;)调用,java,java-native-interface,ejb,ejb-3.0,weblogic-10.x,Java,Java Native Interface,Ejb,Ejb 3.0,Weblogic 10.x,我正在尝试使用JNI从EJB调用windows上的本机库(dll)。我读过很多博客,网站建议EJB规范中不允许从EJB进行JNI调用。不过也有特定于供应商的例外情况。我使用weblogic作为EJB容器。如果你能在这方面给我提供指导/建议。我知道资源适配器是一种选择,但对于简单的需求来说,实现它是一项艰巨的任务。这是我的方法 我开发了一个简单的JNI,它调用C++本地库(也由我构建)并输出输出: 类JNI类HeloJiNCPP调用DLL,调用一个原生方法 SayelLoor()/St>>,用C
我开发了一个简单的JNI,它调用C++本地库(也由我构建)并输出输出:
package com.test.services;
import javax.ejb.Remote;
@Remote
public interface TestEJBRemote {
public void helloJNI();
}
会话Bean
package com.test.services;
import javax.ejb.Stateless;
@Stateless(mappedName = "TestEJB")
public class TestEJBBean implements TestEJBRemote {
public void helloJNI(){
new HelloJNICpp(). hello(); // Invoke native method
}
}
包装类充当JNI
package com.test.services;
public class HelloJNICpp {
static {
//System.load("hellocpp"); // hello.dll (Windows) or libhello.so (Unixes)
try{
System.loadLibrary("hellocpp");
}catch( Exception e){
System.out.println("Some problem occurred while loading library.");
}
}
// Native method declaration
private native void sayHello();
// Test Driver
public static void hello() {
new HelloJNICpp().sayHello(); // Invoke native method
}
}
Bean测试客户端
package com.test.client;
import com.test.services.*;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class TestEJBClient {
public static void main (String args[]){
try {
Context ctx = new InitialContext(getInitialContext());
TestEJBRemote testBean = (TestEJBRemote) ctx.lookup("TestEJB#com.test.services.TestEJBRemote");
testBean.helloJNI();
} catch (NamingException e) {
e.printStackTrace();
}
}
private static Hashtable<String, Object> getInitialContext() {
Hashtable<String, Object> properties = new Hashtable<String, Object>();
properties.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
properties.put(Context.PROVIDER_URL, "t3://localhost:7001");
return properties;
}
}
以下是项目结构:
JNIEXPORT void JNICALL Java_com_test_services_HelloJNICpp_sayHello (JNIEnv *env, jobject thisObj)
从EJB调用/加载本机库在技术上是不可能的,还是我遗漏了什么?我确信塔尔静态块没有抛出任何异常,因为它有一个try-catch块,并且在weblogic级别没有捕获任何异常
提前感谢。我从各个角度进行了调查,记住了所有方面,最终能够解决问题。我从技术上理解,从会话bean(部署在Weblogic上)调用JNI库是可能的,但是从EJB规范的角度来看,这可能不是一种建议的做法,因为本机库调用使bean系统依赖于它,并且它不再具有可移植性 由于UnsatifiedLinkError具有多种性质,因此
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
看起来运行时JNI绑定失败了。我采取的解决问题的方法:
检查java.library.path-
按照朋友们的建议,我写了
System.getProperty("java.library.path")
在bean中,确保我的dll已经存在。在我的例子中,它是OS库加载路径C:/Windows/System32(尽管我在执行JNI的本地实践文件夹中也有这个库)
检查文件夹权限
包含本机库的文件夹也具有读写执行权限
容器库路径
我将库放在[WEBLOGIC\u HOME]/server/lib中,这样在运行时容器就可以启动了。即使这样也不能解决问题
JNI签名
我想重温我的JNI头文件和本机实现。我在创建头文件(HelloJNICpp.h)时发现,源JAVA类不包含package语句。后来我加入了package语句,以便从Eclipse运行它。这是一个问题,是我自己的代码。最初是这样的:
JNIEXPORT void JNICALL Java_HelloJNICpp_sayHello (JNIEnv *env, jobject thisObj)
使用适当的包结构创建之后:
JNIEXPORT void JNICALL Java_com_test_services_HelloJNICpp_sayHello (JNIEnv *env, jobject thisObj)
这就成功了!我的学习:
EJB应该通过JCA资源适配器调用本机代码
JNI-RA-HOWTO中有一个示例:您的库是否位于-Djava.library.path上?在ejb方法中调用
System.getProperty(“java.library.path”)
。也许它被某种方式覆盖了……IIRC,在JVM加载DLL之前,您需要授予DLL权限。@xwid正如我所提到的,“java.libry.path”是我的C:\Windows\System32文件夹,我也放在了服务器库中。@AlexBarker我已经授予DLL完全权限,仍然是相同的错误。DLL和文件夹的任何其他标识都需要权限。此外,您显示的屏幕截图显示了C:\practice中的hellocpp.dll文件,该文件不是C:\Windows\System32。java.library.path属性告诉java在哪里查找System.load引用的JNI库。。。这与操作系统库加载路径不同!请遵循xwid的建议并检查java.library.path。我怀疑您忘记设置该属性或将其设置为不正确的值。