EJB中的IoC抛出ClassNotFoundException和'无法编组EJB参数'

时间:2017-05-04 10:25:33

标签: java java-ee dependency-injection

我有以下设置:

我们正在JBoss 6.4上运行一个应用程序,我们在其中部署了包含业务逻辑的EJB。还部署了一场战争,其中一些网络服务和网络套件存在。

现在我想要这样的事情:

在耳边

@Remote
public interface EventConsumer extends Serializable {

    void onEventMessage(Topic topic, String message, String principalName);

    void onErrorMessage(Topic topic, Throwable t, String principalName);

}

public class EventLogImpl {

    private final List<EventConsumer> consumers;

    public EventLogImpl() {
        this.consumers = new ArrayList<>();
    }

    public void registerEventConsumer(EventConsumer consumer) {
        consumers.add(consumer);
    }
    // other stuff...
}

整个事情都暴露为EJB:

@Singleton
@Startup
@Remote(EventLog.class)
@TransactionAttribute(TransactionAttributeType.REQUIRED)
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class EventLogEJB implements EventLog {

    private final EventLogImpl delegate = new EventLogImpl();

    @Override
    @Lock(LockType.WRITE)
    public void registerEventConsumer(EventConsumer consumer) {
        delegate.registerEventConsumer(consumer);
    }

    // stuff

}
在战争方面

@ServerEndpoint("/ws/eventLog/")
@Stateless
public class EventLogWebsocket implements EventConsumer {

    private static final long serialVersionUID = 1L;
    private final EventLog eventLogService;

    public EventLogWebsocket() {
        eventLogService = createEventLogService();
    }

    @OnOpen
    public void open(Session session) {
        eventLogService.registerEventConsumer(this);
    }

    // other ws stuff

    @Override
    public void onEventMessage(Topic topic, String message, String principalName) {
        System.out.println(message);
    }

    @Override
    public void onErrorMessage(Topic topic, Throwable t, String principalName) {
        System.out.println(message);
    }

    private EventLog createEventLogService() {
        EventLog logService = // some proxy stuff since its remote. works fine
        return logService;
    }

}

问题

不幸的是,当调用ws open方法时,这不起作用:

ERROR [xyz.ws.EventLogWebsocket] (http-/0.0.0.0:8280-17) error occurred in websocket: java.lang.reflect.InvocationTargetException
...
Caused by: java.lang.RuntimeException: JBAS014154: Failed to marshal EJB Parameters
...
Caused by: java.lang.ClassNotFoundException: xyz.ws.EventLogWebsocket from [Module "deployment.abc-app-0.6.0-SNAPSHOT.ear.abc-infrastructure-ejb-0.6.0-SNAPSHOT.jar:main" from Service Module Loader]
...

调试到jboss ModuleClassLoader显示EJB无法加载EventLogWebsocket类。但是在这个IoC设置中,这就是我想要的:不关心这个特定接口的实现......

现在我没有看到解决方案......你呢? :)

1 个答案:

答案 0 :(得分:0)

您需要记住@Remote方法调用使用RMI,因此:

  1. 所有方法参数和返回值必须为java.io.Serializable

  2. 方法参数由 value 传递,而不是引用,因此接收方法获取对象的副本 - 而不是实际对象。

  3. 如您所见,最初的电话:

     eventLogService.registerEventConsumer(this);
    

    有问题:

    当EJB端尝试反序列化consumer对象时,它会尝试重新创建EventLogWebsocket的副本,但此类在EAR中不可用,并且失败。

    此外,EventLogWebsocket参数必须是可序列化的对象。它声称是可序列化的,但并不是因为它包含那个不可序列化的EventLog对象。

    即使您纠正了所有这些问题,它仍然无法正常工作,因为EJB有EventLogWebsocket副本,因此无论如何都不会发送任何事件通知。

    因此,您需要做的第一件事就是摆脱@Remote界面。这意味着您必须在EAR中包含WAR并使用@Local接口。

    但是你仍需要警惕,因为EAR / WAR文件中的类可以看到EAR / EJB类,但反过来却不正确 - EAR / EJB类无法看到EAR / WAR文件中的类。

    如果您在重新打包后仍然遇到类加载问题,那么请考虑将所有内容放入WAR文件中并完全丢失EAR。