在《實現生產者P2P&subpub兼容模式》中實現了生產者兩種消息類型的兼容模式,在消費者中對於單應用同樣有這樣的需求,我們需要能夠在一個應用內同時消費隊列和發佈訂閱兩個類型的消息。
本章概要
1、回顧;
2、編碼;
3、驗證;
回顧
在springboot下,目前我們切換隊列和發佈訂閱模式均通過spring.jms.pub-sub-domain屬性配置。《實現生產者P2P&subpub兼容模式》中我們直接定了兩個JmsTemplate,並通過調用setPubSubDomain(isPubSubDomain);分別設置其應用類型。同理在我們定義的DefaultJmsListenerContainerFactory中同樣有
factory.setPubSubDomain(jmsProperties.isPubSubDomain());方法對其進行設置,我們僅需定義兩個不同的DefaultJmsListenerContainerFactory對應不同的setPubSubDomain設置即可滿足本章的實踐驗證,下面開始編碼驗證。
編碼
1、在JmsListenerContainerConfiguration中註冊兩個DefaultJmsListenerContainerFactory實例:
@Bean(name = { "jmsListenerContainerFactory4Topic" })
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory4Topic() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(cachingConnectionFactory);
factory.setPubSubDomain(true);
if (this.transactionManager != null) {
factory.setTransactionManager(transactionManager);
} else {
factory.setSessionTransacted(Boolean.valueOf(true));
}
JmsProperties.Listener listener = jmsProperties.getListener();
factory.setAutoStartup(listener.isAutoStartup());
if (listener.getAcknowledgeMode() != null) {
factory.setSessionAcknowledgeMode(Integer.valueOf(listener.getAcknowledgeMode().getMode()));
}
String concurrency = listener.formatConcurrency();
if (concurrency != null)
factory.setConcurrency(concurrency);
return factory;
}
@Bean(name = { "jmsListenerContainerFactory4Queue" })
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory4Queue() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(cachingConnectionFactory);
factory.setPubSubDomain(false);
if (this.transactionManager != null) {
factory.setTransactionManager(transactionManager);
} else {
factory.setSessionTransacted(Boolean.valueOf(true));
}
JmsProperties.Listener listener = jmsProperties.getListener();
factory.setAutoStartup(listener.isAutoStartup());
if (listener.getAcknowledgeMode() != null) {
factory.setSessionAcknowledgeMode(Integer.valueOf(listener.getAcknowledgeMode().getMode()));
}
String concurrency = listener.formatConcurrency();
if (concurrency != null)
factory.setConcurrency(concurrency);
return factory;
}
2、修改上一章節中的消費者代碼,實現隊列與發佈定義消息的錯位消費生產:
@Component
public class Consumer {
@Autowired
@Qualifier(value="jmsQueueMessagingTemplate")
private JmsMessagingTemplate jmsQueueMessagingTemplate;
@Autowired
@Qualifier("consuqueue")
private Queue queue;
@Autowired
@Qualifier(value="jmsTopicMessagingTemplate")
private JmsMessagingTemplate jmsTopicMessagingTemplate;
@Autowired
@Qualifier(value="responsetopic")
private Topic topic;
@Autowired
private UserRepository userRepository;
/**
* 監聽queue隊列消息並生產發佈訂閱responsetopic消息,同時生產3倍數量的用戶信息;事務生效
* @param text
* @throws Exception
*/
@JmsListener(destination = "my.queue",containerFactory="jmsListenerContainerFactory4Queue")//ActiveMQ.DLQ
public void receiveQueue(String text) throws Exception {
System.out.println("消費者:來源於生產者的消息:"+text);
this.jmsTopicMessagingTemplate.convertAndSend(this.topic, "生產者辛苦生產的發佈訂閱消息成果");
System.out.println("生產者2:辛苦生產發佈訂閱消息成果");
List<User> list=new ArrayList<User>(10);
list.add(new User("111","111"));
list.add(new User("12211","222"));
list.add(new User("333","333"));
for(User user:list){
userRepository.save(user);
}
// throw new Exception("出現異常啦");
}
/**
* 監聽topic發佈訂閱消息並生產consuqueue隊列消息,同時生產3倍數量的用戶信息;事務生效
* @param text
* @throws Exception
*/
@JmsListener(destination = "my.topic",containerFactory="jmsListenerContainerFactory4Topic")//ActiveMQ.DLQ
public void receiveTopic(String text) throws Exception {
System.out.println("消費者:來源於生產者2的消息:"+text);
this.jmsQueueMessagingTemplate.convertAndSend(this.queue, "生產者辛苦生產的點對點消息成果");
System.out.println("生產者2:辛苦生產的點對點消息成果");
List<User> list=new ArrayList<User>(10);
list.add(new User("111","111"));
list.add(new User("12211","222"));
list.add(new User("333","333"));
for(User user:list){
userRepository.save(user);
}
// throw new Exception("出現異常啦");
}
}
驗證
1、首先查看目前的數據信息
用戶數據
隊列消息
消息表
暫時沒有發佈訂閱消息。
2、預期:
2.1、每消費一個queue會生產一個responsetopic消息,故MQ控制檯應該是4個responsetopic消息、12個用戶數據;
2.2、每消費一個topic消息會生產一個consuqueue消息,故啓動topic消息生產者後查看其控制檯具體生產數量,在MQ控制檯是否生產了對應數量的consuqueue消息、以及3倍數量的用戶數據;
3、啓動消費者監聽:
發佈訂閱消息部分
隊列消息部分
數據庫用戶:原來24+消費4個topic*3+消費4個queue*3=48
數據庫消息表:
總結:通過自定義不同類型應用的DefaultJmsListenerContainerFactory實例實現了單應用內同時消費隊列和發佈訂閱兩個類型消息,並且每個監聽內部仍然滿足分佈式事務約束。我們也看到了消息表中沒有被消費的發佈訂閱消息並不存在,那是由於沒有持久化的訂閱者,故後面章節將實現持久化訂閱者。