在websphere中查找本地EJB的正确方法 - 获取ClassCastException [英] Correct way to lookup local EJB in websphere - Getting ClassCastException

查看:159
本文介绍了在websphere中查找本地EJB的正确方法 - 获取ClassCastException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个由本地和远程接口公开的EJB

I have an EJB which is exposed by both local and remote interfaces

package com.sam.enqueue;

import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Singleton;

@Singleton
@Local(SamEnqueueLocal.class)
@Remote(SamEnqueueRemote.class)
public class SamEnqueue implements SamEnqueueRemote, SamEnqueueLocal {


}


// remote interface
package com.sam.enqueue;

import javax.ejb.Remote;

@Remote
public interface SamEnqueueRemote {


}

// local interface
package com.sam.enqueue;

@Local
public interface SamEnqueueLocal {



}

我的app容器是websphere 8.0,我没有覆盖服务器分配的默认JNDI名称。
在服务器启动期间,我在日志中获得以下默认绑定:

My app container is websphere 8.0 and I am not overriding the default JNDI names which the server assigns. During server startup I get the following default bindings in logs:

CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueRemote interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application.  The binding location is: ejb/SAM_ENQUEUE/SAM_ENQUEUE.jar/SamEnqueue#com.sam.enqueue.SamEnqueueRemote
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueRemote interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application.  The binding location is: com.sam.enqueue.SamEnqueueRemote
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueRemote interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application.  The binding location is: java:global/SAM_ENQUEUE/SamEnqueue!com.sam.enqueue.SamEnqueueRemote
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueLocal interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application.  The binding location is: ejblocal:SAM_ENQUEUE/SAM_ENQUEUE.jar/SamEnqueue#com.sam.enqueue.SamEnqueueLocal
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueLocal interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application.  The binding location is: ejblocal:com.sam.enqueue.SamEnqueueLocal
CNTR0167I: The server is binding the com.sam.enqueue.SamEnqueueLocal interface of the SamEnqueue enterprise bean in the SAM_ENQUEUE.jar module of the SAM_ENQUEUE application.  The binding location is: java:global/SAM_ENQUEUE/SamEnqueue!com.sam.enqueue.SamEnqueueLocal

lookup类只是同一服务器中不同EAR中的一个简单java类,代码如下:

The lookup class is just a simple java class in a different EAR in the same server with the following code:

Context ctx = new InitialContext();
Object local = ctx.lookup("java:global/SAM_ENQUEUE/SamEnqueue!com.sam.enqueue.SamEnqueueLocal");

SamEnqueueLocal samEnqueue = (SamEnqueueLocal) local;

查找正在使用本地的三个JNDI名称中的任何一个,但它没有被转换为 SamEnqueueLocal 。异常跟踪是:

The lookup is working with any of the three JNDI names for the local but it's not getting cast to SamEnqueueLocal. The exception trace is:

SystemErr     R java.lang.ClassCastException: com.sam.enqueue.EJSLocal0SGSamEnqueue_cf56ba6f incompatible with com.sam.enqueue.SamEnqueueLocal

... rest ommited

我做了一个共享库并将目标EAR的存根放入其中。该库是源查找EAR的类路径,其中 Classes首先加载了本地类加载器(父级最后一个)策略。图书馆不是孤立的。如果我删除存根,我会按预期得到 java.lang.ClassNotFoundException:com.sam.enqueue.SamEnqueueLocal

I've made a shared library and put the stub of destination EAR in it. The library is the classpath of the source lookup EAR with the Classes loaded with local class loader first (parent last) policy. The library is not isolated. If I remove the stub, I get a java.lang.ClassNotFoundException: com.sam.enqueue.SamEnqueueLocal as expected.

更新:

使用依赖注入时:

@EJB(lookup="ejblocal:com.sam.enqueue.SamEnqueueLocal")
private SamEnqueueLocal samEnqueueLocal;

我得到的错误是:

javax.ejb.EJBException: Injection failure; nested exception is: java.lang.IllegalArgumentException: Can not set com.sam.enqueue.SamEnqueueLocal field com.some.SomeBean.samEnqueueLocal to com.sam.enqueue.EJSLocal0SGSamEnqueue_cf56ba6f
Caused by: java.lang.IllegalArgumentException: Can not set com.sam.enqueue.SamEnqueueLocal field com.some.SomeBean.samEnqueueLocal to com.sam.enqueue.EJSLocal0SGSamEnqueue_cf56ba6f

所以它基本相同。

推荐答案

bkail的回答,这些是我遵循的步骤。

From the link provided by in bkail's answer, These are the steps that I followed to make it work.


  1. 取出本地远程界面,即 SamEnqueueRemote SamEnqueueLocal 从我的源EJB jar和包然后进入一个单独的jar文件。虽然只是取出Local接口也可以。

  2. 创建一个共享库并将此jar放入其中。必须隔离共享库,以便调用者和被调用者加载相同版本的类。

  3. 在调用者EAR中,使用查找或注入获取对本地接口的引用。

  4. 将调用者和被调用者都部署到服务器,并确保在两个EAR的类路径中添加共享库。

  1. Take out the Local and Remote interfaces i.e. SamEnqueueRemote and SamEnqueueLocal from my source EJB jar and package then into a separate jar file. Although just taking out the Local interface will also work.
  2. Make a shared library and put this jar into it. The shared library must be isolated so that same version of class is loaded by caller and callee.
  3. In the caller EAR, get a reference to the local interface with either a lookup or injection.
  4. Deploy both the caller and callee to the server and make sure to add the shared library in the classpath of both the EARs.

链接类似。


防止这种情况的一种方法是使用远程接口。正如Paul所提到的那样,当调用者和被调用者在同一个JVM中时会发生优化,所以它并不像在单独的JVM中那样昂贵。 ORB具有类加载器机制,可确保使用与调用的每一侧兼容的类加载器加载调用者和被调用者的类。

One way to prevent this is to use a remote interface. As Paul mentioned, there is optimization that happens when the caller and callee are in the same JVM, so it's not as expensive as if they're in separate JVMs. The ORB has classloader machinery that ensures the classes for the caller and callee are loaded using classloaders compatible with each side of the call.

选项2,包括在内的ejb jar新耳,不会解决问题。即使这两个类在两个类加载器中都可用,但是从被调用者传递给调用者的对象仍将使用另一个应用程序的类加载器进行实例化,并且不能是类型可分配的。与选项3相同。

Option 2, including the ejb jar within the new ear, won't solve the problem. Even though the classes will be available in both classloaders, the object passed by-reference from callee back to caller will still be instanciated using the other application's classloader and will not be type-assignable. Same with Option 3.

使其工作的第二种方法是将调用者和被调用者使用的类放在WAS共享库中并配置要使用的两个应用程序那个共享库。 WAS InfoCenter文档中描述了共享库的主题以及如何配置它们...搜索共享库。

The 2nd way to make it work is to place the classes used by caller and callee in a "WAS shared library" and configure both applications to use that shared library. The subject of shared libraries and how to configure them is described in the WAS InfoCenter documentation...search on "shared library."

使其工作的第三种方法,这是三者中最不可取的,是将WAS服务器类加载器策略更改为每个服务器一个类加载器。正如我在顶部提到的,默认情况是每个应用程序一个类加载器(EAR文件)。更改为每个服务器的一个类加载器可确保所有内容都由同一个类加载器加载,因此类型兼容,但会剥夺应用程序在每个应用程序在其自己的类加载器中产生的隔离/安全性好处。

The 3rd way to make it work, which is the least desirable of the three, is to change the WAS server classloader policy to "one classloader per server." The default, as I mentioned at the top, is "one classloader per application (EAR file)." Changing to one classloader per server ensures that everything gets loaded by the same classloader and is thus type-compatible, but deprives your applications of the isolation/security benefits that come from having each app in its own classloader.

这篇关于在websphere中查找本地EJB的正确方法 - 获取ClassCastException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆