業務背景
我所在公司系統要升級到jdk8, 其中一個工程需要從IBM MQ 切換到ActiveMQ。 消息發送方的消息隊列名稱是配置在數據庫中的,不同的環境有不同的配置,且同一個消息可能有不同的消息隊列名稱(因為是很古老的項目,所以誰也說不清楚為什么有這么多不同的隊列),但是為了在升級過程中不會讓客戶修改任何數據,我們決定從程序入手解決不同對列名稱問題。我們的消息消費端是基于SpringBoot的工程。
思路
雖然消息生產方在數據庫中配置了多個消息隊列,但是我們的消費邏輯是一樣的。所以,我們就要用同一個消息消費者去消費這些隊列中的消息,消息消費流程如下圖。如何注冊達到這樣的效果呢?
activemq.png
注冊bean
我們使用spring常用的注冊bean的方式要么是通過xml文件配置,在啟動過程中加載解析,最終成為容器中的bean, 或者我們使用注解的方式,例如@Controller,@Service, @Resource,@Component,@Bean 等,上面是我們常用的方式。現在我們要通過java代碼的方式去生成bean.
- new一個對象,放到容器中
程序初始化完成后,獲取上下文,直接把實例添加到容器中,然后給這個實例起一個名字。
AnnotationConfigServletWebServerApplicationContext beanFactory = (AnnotationConfigServletWebServerApplicationContext)context;
RootBeanDefinition beanDefinition = new RootBeanDefinition(Person.class);
beanDefinition.setAttribute("name","張老三");
beanFactory.registerBeanDefinition("person",beanDefinition);
- 繼承 BeanDefinitionRegistryPostProcessor
@Configuration
public class DefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
registerListener("1,2,3,4,5,6,7,8,9",new CustomerListener(),beanDefinitionRegistry);
/* this.registerListener("test1",new RSSQLInvoiceUploadAgent(),beanDefinitionRegistry);
this.registerListener("test2",new GPRetrievePaymentAgent(),beanDefinitionRegistry);
this.registerListener("test3",new GPCustomerAgent(),beanDefinitionRegistry);*/
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
}
private void registerListener(String destination, MessageListener queueListener,BeanDefinitionRegistry beanDefinitionRegistry){
if (StringUtils.isEmpty(destination)){
return;
}
String[] jmsQueues = destination.split(",");
String[] beans = beanDefinitionRegistry.getBeanDefinitionNames();
for(int m=0;m<beans.length;m++){
System.out.println(beans[m]);
}
for(int i=0;i<jmsQueues.length;i++){
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(DefaultMessageListenerContainer.class);
beanDefinitionBuilder.addPropertyValue("cacheLevel",Integer.valueOf("1"));
beanDefinitionBuilder.addPropertyValue("concurrentConsumers",Integer.valueOf("1"));
beanDefinitionBuilder.addPropertyValue("connectionFactory",beanDefinitionRegistry.getBeanDefinition("cachingConnectionFactoryConfig"));
beanDefinitionBuilder.addPropertyValue("messageListener",queueListener);
beanDefinitionBuilder.addPropertyValue("destinationName",jmsQueues[i]);
beanDefinitionBuilder.addPropertyValue("receiveTimeout",Long.valueOf("3000"));
beanDefinitionRegistry.registerBeanDefinition(queueListener.getClass().getSimpleName()+i,beanDefinitionBuilder.getBeanDefinition());
}
}
但是最終沒有使用這種方法在我們實際的開發過程中,因為@JmsListener 是支持通過"," 分隔監聽我們需要的消息隊列的。