ApacheTomcatで実行されるWebアプリケーションを喜んで改善しています。メッセージを送受信するために、ActiveMQJMSサーバーが追加されました。
私はすでにメッセージを送受信できますが、受信者側で助けが必要です。
Webアプリは、メッセージを受信するために1つのキューを継続的にリッスンする必要がありますか?
新しいメッセージが到着し、サーバーはそれらに基づいて動作する必要があります。例:DBにデータを追加するか、メッセージを送り返します。
すでにメッセージを送信できます。これはコードです。
ActiveMQConnectionFactory factory = new ActiveMQConnectionFactory("tcp://localhost:61616");
Connection connection = factory.createConnection();
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
Queue queue = session.createQueue("clientQueue");
MessageProducer publisher = session.createProducer(queue);
connection.start();
Message message = null;
message = session.createTextMessage("Text Message");
publisher.send(message);
リクエスト後、すでにメッセージを受信できます(クリック;-))
connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");
connection = connectionFactory.createConnection();
connection.start();
session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
destination = session.createQueue("serverQueue");
consumer = session.createConsumer(destination);
while (true) {
Message message = consumer.receive(300000);
//Do message stuff
}
Webアプリケーションにキューを継続的にリッスンさせるにはどうすればよいですか?推奨される方法は何ですか?
すべての助けに心から感謝します。ありがとう。
編集-ソリューション
DaveHからの提案による現在の実用的なソリューション
メッセージを継続的にリッスンするためにServletContextListenerを追加しました。
web.xml
<listener>
<listener-class>com.test.JMSContextListener</listener-class>
</listener>
リステレン:
public class JMSContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent arg0) {
Thread thread = new Thread(new JMSConnector());
thread.start();
}
@Override
public void contextDestroyed(ServletContextEvent arg0) {
//Nothing
}
}
接続:
public class JMSConnector implements Runnable {
public void run() {
try {
Context context = new InitialContext();
QueueConnectionFactory factory = (QueueConnectionFactory) context.lookup("Java:comp/env/jms/ConnectionFactory");
Connection connection = factory.createConnection();
Queue queue = (javax.jms.Queue) context.lookup("Java:comp/env/jms/serverQueue");
Session session = connection.createSession(false,Session.AUTO_ACKNOWLEDGE);
MessageConsumer consumer = session.createConsumer(queue);
//This MessageListener will do stuff with the message
MessageListenerImpl messageListener = new MessageListenerImpl();
consumer.setMessageListener(messageListener);
connection.start();
// Start connection or nothing will happen!!!
connection.start();
} catch (JMSException ex) {
//TODO
} catch (NamingException ex) {
//TODO
}
}
}
これは推奨される方法ですか、それとも改善する必要がありますか?
すべての助けに心から感謝します。ありがとう。
キューからのメッセージをすでに消費できるコードがある場合(そうしているように見えます)、問題はそのコードをどのように実行するかにあると思います。
フレームワークを使用していないようです。そのため、キューからメッセージを取得できるコードを取得して、アプリケーションサーバーの別のスレッドで実行することをお勧めします。そのスレッドをアプリケーションサーバーの起動時に起動し、アプリケーションサーバーが終了するときにそれ自体を整理します。
アプリサーバーの起動時にスレッドを開始する最も簡単な方法は、ServletContextListenerを導入することです(例 ここ 。)コンテキストリスナーで、キューリスニングコードを別のスレッドで開始します。
編集:この提案されたソリューションを使用し、上記のコードを質問に追加しました。
私はwebApplicationspring-mvcとJMSテンプレートでactiveMQを次のアプローチで使用しています。
<bean id="connectionFactory" class="org.Apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL">
<value>tcp://localhost:61616</value>
</property>
</bean>
<bean id="messageSender" class="xyz.MessageSender"/>
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<property name="connectionFactory" ref="connectionFactory" />
<property name="defaultDestination" ref="destination" />
</bean>
<bean id="destination" class="org.Apache.activemq.command.ActiveMQQueue">
<constructor-arg value="REQUEST_QUEUE" />
</bean>
<bean id="messageListener" class="xtz.MessageListener">
<property name="listenerId" value="1" />
</bean>
<jms:listener-container connection-factory="connectionFactory">
<jms:listener destination="RESPONSE_QUEUE" ref="messageListener" method="messageReceived" />
</jms:listener-container>
以下に示すSenderおよびListenerクラスの実装。
public class MessageSender
{
@Autowired
private JmsTemplate jmsTemplate;
public void sendMessage()
{
jmsTemplate.send(new MessageCreator()
{
public Message createMessage(Session session) throws JMSException
{
MapMessage message = session.createMapMessage();
message.setString("messageType", XXX);
message.setString("jsonMessage", XXXX);
return message;
}
});
}
}
public class MessageListener
{
private int listenerId;
@Override
public void messageReceived(Map<String, Object> message) throws Exception
{
//put your logic here
}
public int getListenerId()
{
return listenerId;
}
public void setListenerId(int listenerId)
{
this.listenerId = listenerId;
}
}
私は春を使って待ち行列を聞いています。リスナーの定義は次のようになります。
<jms:listener-container connection-factory="jmsConnectionFactoryLocal">
<jms:listener destination="QUEUE_NAME" ref="channelManagerSimulatorDefault"/>
</jms:listener-container>
jmsConnectionFactoryLocalは、MQに従って作成する必要があります。私の場合はIBMWebsphereMQだったので、jmsConnectionFactoryLocalの定義は次のようになります。
<bean id="mqConnectionFactoryLocal" class="com.ibm.mq.jms.MQQueueConnectionFactory">
<property name="hostName">
<value>THE_MQ_SERVER_IP</value>
</property>
<property name="port">
<value>MQ_PORT</value>
</property>
<property name="queueManager">
<value>QUEUE_MANAGER_NAME</value>
</property>
<property name="transportType">
<value>1</value>
</property>
</bean>
<bean id="jmsConnectionFactoryLocal" class="org.springframework.jms.connection.UserCredentialsConnectionFactoryAdapter">
<property name="targetConnectionFactory" ref="mqConnectionFactoryLocal"/>
<property name="username" value="USER_NAME"/>
<property name="password" value="PASSWORD"/>
</bean>
activeMQに適切なConnectionFactory実装を見つけて、それを使用する必要があります。リスナーとjmsConnectionFactoryは同じであり、MQプロバイダーから独立しています。
TomcatでJMSキューを構成します: https://martinsdeveloperworld.wordpress.com/2013/03/03/Apache-activemq-and-Tomcat/
Activemq-all-5.xx.jarを$ Tomcat_HOME/libに配置します
@WebListener
で開始されたスレッドでサイクルでリッスンします:
ContextDestroyed時に停止します
@WebListener
@Slf4j
public class JmsMailListener implements ServletContextListener {
private Thread listenerThread = null;
private QueueConnection connection;
@Override
public void contextInitialized(ServletContextEvent sce) {
try {
InitialContext initCtx = new InitialContext();
ActiveMQConnectionFactory connectionFactory =
(ActiveMQConnectionFactory) initCtx.lookup("Java:comp/env/jms/ConnectionFactory");
connectionFactory.setTrustAllPackages(true);
connection = connectionFactory.createQueueConnection();
QueueSession queueSession = connection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
Queue queue = (Queue) initCtx.lookup("Java:comp/env/jms/queue/MailQueue");
QueueReceiver receiver = queueSession.createReceiver(queue);
connection.start();
log.info("Listen JMS messages ...");
listenerThread = new Thread(() -> {
try {
while (!Thread.interrupted()) {
Message m = receiver.receive();
if (m instanceof ObjectMessage) {
ObjectMessage om = (ObjectMessage) m;
MyObject myObject = (MyObject) om.getObject();
log.info("Received MyObject {}", myObject);
...
}
}
} catch (Exception e) {
log.error("Receiving messages failed: " + e.getMessage(), e);
}
});
listenerThread.start();
} catch (Exception e) {
log.error("JMS failed: " + e.getMessage(), e);
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
if (connection != null) {
try {
connection.close();
} catch (JMSException ex) {
log.warn("Couldn't close JMSConnection: ", ex);
}
}
if (listenerThread != null) {
listenerThread.interrupt();
}
}
}