我正在尝试使用JMS 2.0,因此我可以决定是否值得在我的项目中应用。我可以成功创建一个发送/接收应用程序。
现在我想让侦听器在队列中可用时立即收到消息(我的最终目标是让不同的侦听器连接到同一个队列,每个侦听器都有不同的消息选择器。
目前我有这个课程:
package learning.jms;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jms.JMSConnectionFactory;
import javax.jms.JMSConsumer;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.JMSRuntimeException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
@Named(value="senderBean")
@SessionScoped
public class SenderBean implements Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
@Resource(mappedName="queues/myQueue")
private transient Queue myQueue;
@Inject
@JMSConnectionFactory("java:/DefaultJMSConnectionFactory")
private transient JMSContext context;
private String messageText;
private int nextType = 3;
private transient JMSConsumer consumer;
private transient JMSConsumer consumer2;
private transient JMSConsumer consumer3;
public SenderBean() {
}
@PostConstruct
public void setUp(){
}
public String getMessageText() {
return messageText;
}
public void setMessageText(String messageText) {
this.messageText = messageText;
}
public void sendJMSMessageToMyQueue() {
try {
consumer = context.createConsumer(myQueue, "type=1");
consumer.setMessageListener(new ListenerTypeOne());
// consumer2 = context.createConsumer(myQueue, "type=2");
// consumer2.setMessageListener(new ListenerTypeTwo());
//
// consumer3 = context.createConsumer(myQueue, "type=3");
// consumer3.setMessageListener(new ListenerTypeThree());
String text = "Message from producer: " + messageText;
Message m1 = context.createTextMessage(text);
m1.setIntProperty("type", nextType);
System.out.println("producer sending msg type " + nextType + "value: " + text);
nextType = (nextType++%3)+1;
context.createProducer().send(myQueue, m1);
FacesMessage facesMessage =
new FacesMessage("Sent message: " + text);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} catch (JMSRuntimeException | JMSException t) {
System.out.println(t.toString());
}
}
private class ListenerTypeOne implements MessageListener{
@Override
public void onMessage(Message msg) {
try {
System.out.println("Msg received by typeOne:" + msg.getBody(String.class));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class ListenerTypeTwo implements MessageListener{
@Override
public void onMessage(Message msg) {
try {
System.out.println("Msg received by typeTwo:" + msg.getBody(String.class));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private class ListenerTypeThree implements MessageListener{
@Override
public void onMessage(Message msg) {
try {
System.out.println("Msg received by typeThree:" + msg.getBody(String.class));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
我评论了两个消费者,所以我可以专注于做一个工作。 我一直在setMessageListener行上得到以下异常:
javax.jms.IllegalStateException: This method is not applicable inside the application server. See the J2EE spec, e.g. J2EE1.4 Section 6.6
at org.hornetq.ra.HornetQRASession.checkStrict(HornetQRASession.java:1647)
at org.hornetq.ra.HornetQRAMessageConsumer.setMessageListener(HornetQRAMessageConsumer.java:124)
at org.hornetq.jms.client.HornetQJMSConsumer.setMessageListener(HornetQJMSConsumer.java:68)
我不知道是什么导致了这一点,我的搜索没有给我任何额外的信息。 我想这可能与一个组件应该只有一个活动会话的事实有关。在这种情况下,我如何创建多个侦听器来侦听队列?
(如果重要:我正在使用Wildfly 8)
修改 我已经将侦听器创建提取到一个单独的bean,但仍然是同样的错误:
package learning.jms;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.jms.JMSConnectionFactory;
import javax.jms.JMSConsumer;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.Queue;
@ApplicationScoped
public class ListenerOne {
@Inject
@JMSConnectionFactory("java:/DefaultJMSConnectionFactory")
private JMSContext context;
@Resource(mappedName="queues/myQueue")
private Queue myQueue;
private JMSConsumer consumer;
public void setUp() {
consumer = context.createConsumer(myQueue, "type=1");
consumer.setMessageListener(new ListenerTypeOne());
System.out.println("working");
}
private class ListenerTypeOne implements MessageListener{
@Override
public void onMessage(Message msg) {
try {
System.out.println("Msg received by typeOne:" + msg.getBody(String.class));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
答案 0 :(得分:0)
因此,寻找MDB解决了这个问题。 我从我试图创建的消费者的任何痕迹中清理了senderBean类:
package learning.jms;
import java.io.Serializable;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.jms.JMSConnectionFactory;
import javax.jms.JMSContext;
import javax.jms.JMSException;
import javax.jms.JMSRuntimeException;
import javax.jms.Message;
import javax.jms.Queue;
@Named(value="senderBean")
@SessionScoped
public class SenderBean implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Resource(mappedName="queues/myQueue")
private transient Queue myQueue;
@Inject
@JMSConnectionFactory("java:/DefaultJMSConnectionFactory")
private transient JMSContext context;
private String messageText;
private int nextType;
public SenderBean() {
// TODO Auto-generated constructor stub
}
@PostConstruct
public void init(){
nextType=2;
}
public String getMessageText() {
return messageText;
}
public void setMessageText(String messageText) {
this.messageText = messageText;
}
public void sendJMSMessageToMyQueue() {
try {
String text = "Message from producer: " + messageText;
Message m1 = context.createTextMessage(text);
m1.setIntProperty("type", nextType);
nextType = (nextType++%3)+1;
context.createProducer().send(myQueue, m1);
FacesMessage facesMessage =
new FacesMessage("Sent message: " + text);
FacesContext.getCurrentInstance().addMessage(null, facesMessage);
} catch (JMSRuntimeException | JMSException t) {
System.out.println(t.toString());
}
}
}
(注意它只是会话范围所以我可以迭代消息类型“)
并创建了3个MDB
package learning.jms;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup",
propertyValue = "queues/myQueue"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "messageSelector",propertyValue = "type=1")
})
public class ListenerOne implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
System.out.println("Msg received by typeOne: " + msg.getBody(String.class) + " type: " + msg.getIntProperty("type"));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
2:
package learning.jms;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup",
propertyValue = "queues/myQueue"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "messageSelector",propertyValue = "type=2")
})
public class ListenerTwo implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
System.out.println("Msg received by typeTwo: " + msg.getBody(String.class) + " type: " + msg.getIntProperty("type"));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
3:
package learning.jms;
import javax.ejb.ActivationConfigProperty;
import javax.ejb.MessageDriven;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageListener;
@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationLookup",
propertyValue = "queues/myQueue"),
@ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "messageSelector",propertyValue = "type=3")
})
public class ListenerThree implements MessageListener {
@Override
public void onMessage(Message msg) {
try {
System.out.println("Msg received by typeThree: " + msg.getBody(String.class) + " type: " + msg.getIntProperty("type"));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
现在,他们会自动侦听队列中与其选择器匹配的消息。
感谢@prabugp的帮助:)
答案 1 :(得分:0)
上述错误可能是因为您尝试在同一容器内使用客户端并从基于JCA的连接工厂获取连接工厂。
案例1:如果客户端远程到jms服务器,则建议使用jms / RemoteConnectionFactory,并且不会再现上述问题。
案例2:如果客户端位于同一容器中,则首选基于JCA的连接工厂java / JmsXA的连接。由于JEE 7规范在第6:7节中存在限制,JEE服务器不允许EJB / Web应用程序具有多个活动会话,即您不能拥有旧版JMS应用程序。
例如:在方法中:
public void startConnection() {
try {
TopicConnectionFactory connectionFactory = (TopicConnectionFactory) getConnectionFactory();
topicConnection = connectionFactory.createTopicConnection();
topicSession = topicConnection.createTopicSession(false, javax.jms.Session.AUTO_ACKNOWLEDGE);
subscriber = topicSession.createSubscriber(messageTopic, selector, true);
MessageListener messageListener = new MessageListener(this);
// Code to set message listener.
subscriber.setMessageListener(messageListener);
topicConnection.start();
} catch (Exception e) {
LOG.error(e, e);
closeConnection();
throw new RuntimeException(e);
}
}
如果以上代码的连接工厂来自 @Resource(mappedName =“java:jboss / exported / jms / RemoteConnectionFactory”)
然后上面的代码将工作。但是,如果我们将连接工厂更改为 // @ Resource(mappedName =“java:/ JmsXA”)
然后会抛出上面的错误。
因此,如果您的客户端位于同一容器中,则应使用MDB。由于容器需要控制连接对象以支持两阶段提交协议。
答案 2 :(得分:0)
我对此的看法是,你不能在JSF bean中有一个消息监听器,因为bean生命周期是由web容器控制的。
MDB是唯一由消息驱动的组件,但是JSF MB(如EJB或servlet)无法监听消息,它们会直播#34;在请求的上下文中,容器创建,激活,钝化或销毁实例。
但是,您可以在请求的上下文中使用receive(),并在客户端设置一些autorefresh,以实现服务器端驱动的流。