【发布时间】:2014-06-26 13:44:56
【问题描述】:
我正在尝试使用 JNI 从 EJB 调用 windows (dll) 上的本机库。我已经阅读了很多博客和网站建议在 EJB 规范中不允许从 EJB 进行 JNI 调用。但是有供应商特定的例外。我使用 weblogic 作为 EJB 容器。如果你能在这个领域指导/建议我。我知道资源适配器是一种选择,但要实现简单的要求是一项艰巨的任务。这是我的方法。
我开发了一个简单的 JNI,它调用一个 C++ 本地库(也是我构建的)并打印输出:
所以 JNI 类 HelloJNICpp 调用 dll 并调用本地方法 sayHello(),用 C++ 实现,它给出了输出
现在,我实现了一个会话 bean (TestEJBBean.java),一个由 bean 调用的包装类 HelloJNICpp.java(如 JNI)。最后一个独立的java客户端TestEJBClient.java来测试bean,是否可以调用,是否可以调用native。
这里是代码详情:
远程接口
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;
}
}
我将 dll 库放置在所有可能的位置,例如 java 库路径可以包括 C:\Windows\System32 、weblogic 域库,甚至我将它与 EJB 应用程序捆绑并部署它。当我执行客户端时,我得到 UnsatisfiedLink 错误。
Exception in thread "main" javax.ejb.EJBException: EJB Exception: ; nested exception is:
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V; nested exception is: java.rmi.RemoteException: EJB Exception: ; nested exception is:
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
java.rmi.RemoteException: EJB Exception: ; nested exception is:
java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
at weblogic.rjvm.ResponseImpl.unmarshalReturn(ResponseImpl.java:237)
at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:348)
at weblogic.rmi.cluster.ClusterableRemoteRef.invoke(ClusterableRemoteRef.java:259)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl_1036_WLStub.helloJNI(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at weblogic.ejb.container.internal.RemoteBusinessIntfProxy.invoke(RemoteBusinessIntfProxy.java:85)
at $Proxy0.helloJNI(Unknown Source)
at com.test.client.TestEJBClient.main(TestEJBClient.java:14)
Caused by: java.lang.UnsatisfiedLinkError: com.test.services.HelloJNICpp.sayHello()V
at com.test.services.HelloJNICpp.sayHello(Native Method)
at com.test.services.HelloJNICpp.hello(HelloJNICpp.java:19)
at com.test.services.TestEJBBean.helloJNI(TestEJBBean.java:9)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at com.bea.core.repackaged.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:310)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:182)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:149)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.oracle.pitchfork.spi.MethodInvocationVisitorImpl.visit(MethodInvocationVisitorImpl.java:34)
at weblogic.ejb.container.injection.EnvironmentInterceptorCallbackImpl.callback(EnvironmentInterceptorCallbackImpl.java:54)
at com.oracle.pitchfork.spi.EnvironmentInterceptor.invoke(EnvironmentInterceptor.java:42)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.bea.core.repackaged.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:131)
at com.bea.core.repackaged.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:119)
at com.bea.core.repackaged.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:171)
at com.bea.core.repackaged.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:204)
at $Proxy200.helloJNI(Unknown Source)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl.__WL_invoke(Unknown Source)
at weblogic.ejb.container.internal.SessionRemoteMethodInvoker.invoke(SessionRemoteMethodInvoker.java:40)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl.helloJNI(Unknown Source)
at com.test.services.TestEJBBean_vdl7a8_TestEJBRemoteImpl_WLSkel.invoke(Unknown Source)
at weblogic.rmi.internal.BasicServerRef.invoke(BasicServerRef.java:667)
at weblogic.rmi.cluster.ClusterableServerRef.invoke(ClusterableServerRef.java:230)
at weblogic.rmi.internal.BasicServerRef$1.run(BasicServerRef.java:522)
at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:363)
at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:146)
at weblogic.rmi.internal.BasicServerRef.handleRequest(BasicServerRef.java:518)
at weblogic.rmi.internal.wls.WLSExecuteRequest.run(WLSExecuteRequest.java:118)
at weblogic.work.ExecuteThread.execute(ExecuteThread.java:256)
at weblogic.work.ExecuteThread.run(ExecuteThread.java:221)
这是项目结构:
从技术上讲,从 EJB 调用/加载本机库是不可能的,还是我遗漏了什么?我确信静态块没有抛出任何异常,因为它有一个 try-catch 块,并且在 weblogic 级别没有捕获到异常。
提前致谢。
【问题讨论】:
-
你的库在 -Djava.library.path 上吗?在您的 ejb 方法中调用
System.getProperty("java.library.path")。也许它会以某种方式被覆盖...... -
IIRC,您需要先授予DLL权限,然后JVM才能加载它。
-
@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。我怀疑您忘记设置该属性或将其设置为不正确的值。
标签: java java-native-interface ejb ejb-3.0 weblogic-10.x