如何通过application.properties动态添加多个Simplemessagelistenercontainer

时间:2015-10-23 12:28:31

标签: spring-amqp spring-rabbit

下面是我们的程序,我们通过application.properties中的属性为不同的队列创建多个容器。但现在它是静态的,当添加另一个属性时,我们必须更改代码。

我想动态添加容器。我研究了几种解决方案。

1.使用BeanFactory.registerSingleton方法,但它无法接收生命周期回调,因此我不确定容器是否可以正常关闭。

2.使用BeanFactoryPostRegistor,但它需要构建一个BeanDefinition,我不知道如何为SimpleMessageListenerContainer构造一个BeanDefinition,因为它将由SimpleMessageListenrContainerFactory创建。

有人能给我更好的解决方案吗?动态添加bean,SimpleMessageListenerContainer可以正常启动和关闭吗?

@Bean
@ConditionalOnProperty(name = "pmc.multiple.hypervisor.reply.routerkey.kvm")
public SimpleMessageListenerContainer kvmReplyQueueConsumer() {
    return getSimpleMessageListenerContainer(environment
            .getProperty("pmc.multiple.hypervisor.reply.routerkey.kvm"));
}

@Bean
@ConditionalOnProperty(name = "pmc.multiple.hypervisor.reply.routerkey.vmware")
public SimpleMessageListenerContainer vmwareReplyQueueConsumer() {
    return getSimpleMessageListenerContainer(environment
            .getProperty("pmc.multiple.hypervisor.reply.routerkey.vmware"));
}

@Bean
@ConditionalOnProperty(name = "pmc.multiple.hypervisor.reply.routerkey.powervc")
public SimpleMessageListenerContainer powervcReplyQueueConsumer() {
    return getSimpleMessageListenerContainer(environment
            .getProperty("pmc.multiple.hypervisor.reply.routerkey.powervc"));
}



@Autowired
private SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory;

private SimpleMessageListenerContainer getSimpleMessageListenerContainer(String queueName){
return simpleRabbitListenerContainerFactory.createContainerInstance();
}

1 个答案:

答案 0 :(得分:0)

获取所需的所有属性(例如通过regexp),然后注册所需的bean。那里有2个独立的任务(1)如何获取Spring属性(2)如何动态注册bean

1)以'Spring way'迭代属性:

@Autowired
Properties props;
....
for(Entry<Object, Object> e : props.entrySet()) {
    if( /*some code to match*/ ){
       //dispatch bean creation
    }
}

2)您可以通过以下方式动态创建bean:

public MyClassPostRegister implements BeanFactoryPostProcessor {

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        //create bean definition:
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(MyBeanClass.class);
        beanDefinition.setLazyInit(false);
        beanDefinition.setAbstract(false);
        beanDefinition.setAutowireCandidate(true);
        beanDefinition.setScope("prototype");
        beanFactory.registerBeanDefinition("dynamicBean",beanDefinition);
}

评论后的附录@GrapeBaBa

其实我用simpleRabbitListenerContainerFactory.createContainerInstance()创建容器,所以如何转换为使用beanDefinition - 请注意标有(!!!)的行

创建自己的组件

@Component
public class MyClassPostRegister implements BeanFactoryPostProcessor {
@Autowired 
Properties props; //this gives you access to all properties
//following is example of filter by name
static final Pattern myInterestingProperties = 
   Pattern.compile("pmc\\.multiple\\.hypervisor\\.reply\\.routerkey\\..+");

添加后期处理程序:

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
    //iterate through properties
    for(Entry<Object, Object> e : props.entrySet()) {
        Matcher m = myInterestingProperties.matcher(e.key);
        if( !m.matches() )
            continue;
        //create bean definition:
        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
        beanDefinition.setBeanClass(SimpleMessageListenerContainer.class);
        beanDefinition.setLazyInit(false);
        beanDefinition.setAbstract(false);
        beanDefinition.setAutowireCandidate(true);
        beanDefinition.setScope("prototype");
        //!!! Now specify name of factory method
        beanDefinition.setFactoryMethodName("getSimpleMessageListenerContainer");
        //!!! Now specify factory arguments:
        ConstructorArgumentValues v = new ConstructorArgumentValues();
        v.addGenericArgumentValue( e.getKey() ); //string 
        beanDefinition.getConstructorArgumentValues().add( v );

        beanFactory.registerBeanDefinition("dynamicBean",beanDefinition);            
    } 

}