繁体   English   中英

EJB到JNI(C ++)的调用

[英]EJB to JNI (C++) call

我正在尝试使用JNI从EJB调用Windows(dll)上的本机库。 我读过很多博客和网站,建议EJB规范中不允许从EJB进行JNI调用。 但是,有特定于供应商的例外。 我正在使用weblogic作为EJB容器。 如果您可以在这方面指导/建议我。 我知道资源适配器是一个选项,但是对于简单的要求,它是一项艰巨的任务。 这是我的方法。

我开发了一个简单的JNI,它调用了C ++本机库(也由我构建)并打印输出:

在此处输入图片说明

因此,JNI类HelloJNICpp调用dll并调用用C ++实现的本地方法sayHello()

现在,我实现了一个会话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域lib,甚至我将其与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级别中未捕获任何异常。

提前致谢。

我从各个角度进行了调查,牢记所有方面,终于能够解决问题。 我从技术上理解可以从会话bean(在Weblogic上部署)中调用JNI库,但是从EJB规范的角度来看这可能不是建议的做法,因为本机库调用使bean系统依赖于它,更便携。

由于UnsatisfiedLinkError具有多种性质,因此以下内容

 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_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)

这有效! 我的经验:

  1. 因此,在使用具有打包结构的JNI代码时,必须格外小心。
  2. java.library.path属性是JNI中的游戏规则改变者
  3. Eclispe Java运行时和JNI运行时必须相同
  4. 对于C ++,我注意到除了本地库之外,我还必须在java.library.path中放置一些其他与系统相关的库。 它们用于链接MinGW编译器套件。 可以通过运行dependencyWalker来跟踪它们。

EJB应该通过JCA资源适配器调用本机代码。

JNI-RA-HOWTO中有一个示例: https : //wiki.ow2.org/jonas/Wiki.jsp? page =JNIRAHOWTO

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM