我有以下设置:
我们正在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设置中,这就是我想要的:不关心这个特定接口的实现......
现在我没有看到解决方案......你呢? :)
答案 0 :(得分:0)
您需要记住@Remote方法调用使用RMI,因此:
所有方法参数和返回值必须为java.io.Serializable
。
方法参数由 value 传递,而不是引用,因此接收方法获取对象的副本 - 而不是实际对象。
如您所见,最初的电话:
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。