@JmsListenerアノテーションに基づいてパブリッシュ/サブスクライブの例を作成しようとしています: https://github.com/lkrnac/book-eiws-code-samples/tree/master/05-jms/0515-publish-サブスクライブ
関連するコードスニペット:
@Slf4j
@SpringBootApplication
@EnableScheduling
public class JmsPublishSubscribeApplication {
public static void main(String[] args) throws InterruptedException {
SpringApplication.run(JmsPublishSubscribeApplication.class, args);
}
@Bean
public ActiveMQTopic simpleTopic() {
return new ActiveMQTopic("simpleTopic");
}
}
@Component
public class SimpleMessageListener1 {
@JmsListener(destination = "simpleTopic")
public void readMessage(String message) {
//....
}
}
@Component
public class SimpleMessageListener2 {
@JmsListener(destination = "simpleTopic")
public void readMessage(String message) {
//....
}
}
問題は、この動作を取得することです。
2015-05-17 20:07:04.985 INFO 22983 --- [pool-1-thread-1] n.l.b.e.chapter05.SimpleMessageSender : Sending message: simple message
2015-05-17 20:07:05.070 INFO 22983 --- [enerContainer-1] n.l.b.e.c.JmsPublishSubscribeApplication : Message Received: simple message via listener 2
2015-05-17 20:07:05.975 INFO 22983 --- [pool-1-thread-1] n.l.b.e.chapter05.SimpleMessageSender : Sending message: simple message
2015-05-17 20:07:05.986 INFO 22983 --- [enerContainer-1] n.l.b.e.c.JmsPublishSubscribeApplication : Message Received: simple message via listener 1
2015-05-17 20:07:06.975 INFO 22983 --- [pool-1-thread-1] n.l.b.e.chapter05.SimpleMessageSender : Sending message: simple message
2015-05-17 20:07:06.987 INFO 22983 --- [enerContainer-1] n.l.b.e.c.JmsPublishSubscribeApplication : Message Received: simple message via listener 2
2015-05-17 20:07:07.975 INFO 22983 --- [pool-1-thread-1] n.l.b.e.chapter05.SimpleMessageSender : Sending message: simple message
2015-05-17 20:07:07.994 INFO 22983 --- [enerContainer-1] n.l.b.e.c.JmsPublishSubscribeApplication : Message Received: simple message via listener 1
ただし、トピックの定義により、各メッセージは両方のリスナーによって消費される必要があります。何が足りないのですか?
@JmsListener
を使用する場合は、拡張するDefaultMessageListenerContainer
を使用します JmsDestinationAccessor
デフォルトではpubSubDomain
がfalse
に設定されています。このプロパティがfalseの場合、キューで動作しています。トピックを使用する場合は、このプロパティ値をtrue
に設定する必要があります。
Spring Boot を使用しているので、spring.jms.pub-sub-domain
プロパティをapplication.properties
に追加し、それをtrue
に設定することで、このプロパティをtrueに簡単に設定できます。
spring.jms.pub-sub-domain=true
@JmsListener
を使用する場合、jmsListenerContainerFactory
という名前のBeanを探します。それが利用できない場合は、デフォルトのBeanが必要です。独自のBeanを含めて、このプロパティをtrue
にプログラムで設定することもできます。
@Bean
public DefaultMessageListenerContainer jmsListenerContainerFactory() {
DefaultMessageListenerContainer dmlc = new DefaultMessageListenerContainer();
dmlc.setPubSubDomain(true);
// Other configuration here
return dmlc;
}
これはもちろん機能しますが、より多くの作業が必要になります。これに関する詳細は、 @EnableJms
アノテーション のドキュメントに記載されています。
@JmsListener
のデフォルトの宛先タイプをQueue
からTopic
に切り替えることは、プロパティを変更したりXMLを使用したりすることなく、Javaで完全に実行できます。
スプリングガイド には、DefaultMessageListenerContainer
によって提供されるデフォルト設定をカスタマイズするための例が含まれています。
次のようにカスタムBeanを定義する必要があります。
@Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory,
DefaultJmsListenerContainerFactoryConfigurer configurer) {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
// This provides all boot's default to this factory, including the message converter
configurer.configure(factory, connectionFactory);
// You could still override some of Boot's default if necessary.
factory.setPubSubDomain(true);
return factory;
}
これは、@JmsListener
アノテーション付きメソッドで使用できます。
@JmsListener(destination = "mailbox", containerFactory = "myFactory")
public void receiveMessage(Email email) {
// implementation
}