为什么我不能通过 JNDI 使用远程接口访问我的 EJB?

Why can't I access my EJB using the remote interface through JNDI?

我在使用 JNDI 检索 bean 时遇到问题。

我有两只耳朵:客户耳和工人耳。 Clientear 包含 clientejb 和 libejb Workerear 包含 workerejb 和 libejb

该库包含 MyInterface workerejb 包含 bean 和抽象 class clientejb 包含执行查找的客户端代码。

我实现远程接口的 bean

public class MyBean implements MyInterface

它的 JNDI 绑定是

java:global/jndinaming/MyBean!learning.jndinaming.MyInterface

没关系。

现在我想让它扩展一个摘要 class:

public abstract  class MyAbstractClass implements MyInterface
public class MyBean extends MyAbstractClass

因此 JNDI 绑定变为

java:global/jndinaming/MyBean!learning.jndinaming.MyBean

没关系,我调整了字符串和我的代码:

(MyInterface) ctx.lookup("java:global/jndinaming/MyBean!learning.jndinaming.MyInterface");

变成这样:

(MyInterface) ctx.lookup("java:global/jndinaming/MyBean!learning.jndinaming.MyBean");

然后我得到一个 Class 转换异常:

ClassCastException: Cannot cast MyBean$$$view68 (id=938) to MyInterface

接口文件位于客户端和工作项目都可以访问的项目中。

客户端项目包含调用查找方法的代码。

worker 项目有 bean 实现和抽象 class。

这些项目在不同的 ear 文件中,但在同一个 wildfly 容器中。

为什么添加带有抽象 class 的新 "layer" 会导致此 class 转换异常?我能做些什么来解决它?

顺便说一句: 尝试使用

访问
 (MyInterface) ctx.lookup("java:global/jndinaming/MyBean!learning.jndinaming.MyInterface");

导致抛出 nameNotFound 异常

编辑: 这是 bean 的当前状态,抽象 class 和接口:

接口:

import javax.ejb.Remote;

@Remote
public interface MyInterface {
    public void print();

}

摘要Class:

public abstract  class MyAbstractClass implements MyInterface{

}

MyBean

@Stateless
public class MyBean extends MyAbstractClass{

    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }

}

客户代码:

@Stateless
public class TimedBean {
    @Resource
    private SessionContext              ctx;

    @Schedule(second="*/10", minute="*", hour="*")
    public void run() throws NamingException{
            MyInterface c2 = (MyInterface) ctx.lookup("java:global/workerear/workerejb-0.0.1-SNAPSHOT/MyAbstractClassExtender!learning.lib.MyInterface");
        c2.print();
    }

}

从接口中删除@Remote 并将其添加到bean 中解决问题:

public interface MyInterface {
    public void print();

}

@Stateless
@Remote(MyInterface.class)
public class MyBean extends MyAbstractClass{

    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }

}

那么 JNDI 绑定就是这个:

java:global/workerear/workerejb-0.0.1-SNAPSHOT/MyBean!learning.lib.MyInterface

演员表也很成功。

注释处理器检查 implements 子句中的接口以确定 remote/local 接口。因为这种情况下的接口是继承的并且没有在 implements 子句中明确定义,所以注释处理器将假定您的容器的默认行为。

一个解决方案是向您的 Bean 添加一个工具:

@Stateless
public class MyBean extends MyAbstractClass implements MyInterface{
    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }
}

您的回答中所述的另一个方法是在您的 bean 中声明远程接口,而不是:

@Stateless
@Remote(MyInterface.class)
public class MyBean extends MyAbstractClass{

    @Override
    public void print() {
        System.out.println("MyAbstractClassExtender.PRINT");

    }
}

一种方法相对于另一种方法有利也有弊。我发现这个博客很有趣 http://piotrnowicki.com/2013/03/defining-ejb-3-1-views-local-remote-no-interface/