尝试为JMS队列设置侦听器时,此方法在app服务器内部不适用

时间:2015-06-08 08:35:27

标签: java jms

我正在尝试使用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();
            }
        }
    }
}

3 个答案:

答案 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,以实现服务器端驱动的流。