问题
I have 2 applications. One 'main' and a second one with a Remote EJB. The first application calls the Remote EJB in the second one.
Now I want to implement the Observable pattern. But it doesn't seem to work cross-application.
So I want my Observable inside the second application, and my Observers in the first. When I try it, it doesn't seem to work. It only works if I make the Observable and Observers in the same application.
I got another solution, but I think it's dirty. I could use a MDB inside the second application, and publish a message on a Topic, and then consume those messages inside the first application. But then again, that seems kinda dirty.
I'm using JEE7 on a Payara 4.1.1.171 server.
Edit: Because I figured out that triggered Events don't exit an EAR file, I'm now using the MDB method. But that still does not work. More information, this is the package structure of the EAR file.
my-application.ear
+--- common-ejb.jar (EJB)
| +--- MessageDrivenBean.java (Triggers the event)
+--- my-application.jar (EJB)
+--- my-application.war (WEB)
+--- WEB-INF
+--- lib
| +--- common-web.jar (Resources WEB jar)
| +--- SessionBean1 to receive the events
+--- classes
+--- SessionBean2 to receive the events
As you can see there are 2 session beans to receive the events, but none of the 2 actually receive them.
回答1:
Given a message driven bean:
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "java:jboss/queue/SampleQueue")
})
public class EventListener implements MessageListener {
@Inject
@Any
Event<MyEvent> loggedInEvent;
@Override
public void onMessage(Message message) {
if (message instanceof ObjectMessage) {
try {
ObjectMessage objectMessage = (ObjectMessage) message;
loggedInEvent.fire(((MyEvent) objectMessage.getObject()));
} catch (JMSException e) {
e.printStackTrace();
}
}
}
}
where MyEvent is a simple POJO:
public class MyEvent implements Serializable {
private final String payload;
public MyEvent(String payload) {
this.payload = payload;
}
public String getPayload() {
return payload;
}
}
then this @SessionScoped bean:
@SessionScoped
public class EventHandler {
public void handleEvent(@Observes MyEvent myEvent) {
System.out.println(myEvent.getPayload());
}
}
prints the payload String when a MyEvent
object is sent to the queue associated with the EventListener
Any number of observers can be provided.
回答2:
With Payara Server version 171 and Hazelcast enabled, you can fire CDI events and observe them in another application. See the documentation about remote CDI events
If both applications are deployed on the same Payara Server instance, you would fire an event of type MyEvent.class like this:
@Inject
@Outbound(loopBack = true) // loopBack true is required if the observing application is deployed on the same Payara Server instance
Event<MyEvent> event;
...
event.fire(new MyEvent());
And the other application would observe these events with:
public void receiveEvent(@Observes @Inbound MyEvent event) {
}
If the observing application is running on another Payara Server instance in the same Hazelcast cluster, it would also receive the event. In that case, loopBack attribute is not required, but would do no harm either.
Remote CDI events are dispatched via embedded Hazelcast data grid, which will reliably deliver the events to all observing applications across the cluster. The observing application has to be running at the time when the event is fire - a similar behavior to broadcasting events via a JMS topic.
来源:https://stackoverflow.com/questions/43111276/observable-pattern-in-remote-ejb