简体   繁体   中英

spring-amqp Multiple queues with different routingKey

I have recently started learning Spring and spring-amqp so this question might appear very basic so please excuse me for that.

I have multiple queues which are on different hosts and have different QueueName, RoutingKey, vhost, user, password. I am writing the publishing logic for these queues and was not able to decide if I should have one configuration class per queue or can it be done in XML.

The method of creating a class to have all the information about the queue (host, vhost, username etc) is working fine as described in this example . I created a @Configuration class and defined all the beans for that Queue. But then I need to do

ApplicationContext context = new AnnotationConfigApplicationContext(MyQueueConfiguration.class);
AmqpTemplate amqpTemplate  = context.getBean(AmqpTemplate.class);
amqpTemplate.convertAndSend("Hello World!!");

So my requirement is:

  1. Since I have many queues that need to be instantiated at the application startup, once tomcat starts the connections/channels to the queue/rabbit cluster should be established.
  2. Then as soon as there is POST request that comes to my application I need to publish the message to one of the queue based on a POST parameter.

So for each queue do I always need to do:

ApplicationContext context = new AnnotationConfigApplicationContext(HelloWorldConfiguration.class);

Or is there a way to Spring load the all my Queue configuration classes and just use the object like:

    // calling code when I get a POST request
MyQueueConfigurationClass.publishMessage(payload, queueName);

// The implementation code
public boolean publishMessage(String payload, String queueName){

    // Get Bean for the **queueName** somehow
    AmqpTemplate amqpTemplate = context.getBean(AmqpTemplate.class);
    // Use the bean to send the message
    amqpTemplate.convertAndSend(payload);

}
  1. So how can I get the amqpTemplate for the exact queue without doing new AnnotationConfigApplicationContext() everytime?
  2. What is the harm of doing new AnnotationConfigApplicationContext every time a request comes to my service? [I am guessing that creating a new object for each request is not a good idea]

You should not create a new context each time; that is very wasteful.

You can add multiple connection factories (one for each rabbit host) to the root (or web) context, and then use a Routing Connection Factory together with a sendConnectionFactorySelectorExpression to select the proper host based on the message you are sending.

Or, you can simply wire up a different RabbitTemplate for each server.

EDIT :

To use the SimpleRoutingConnectionFactory , do something like...

try {
    SimpleResourceHolder.bind(routingCF, keyForThisMessage);
    rabbitTemplate.convertAndSend(message);
}
finally {
    SimpleResourceHolder.unbind(routingCF);
}

(this will work with an unmodified RabbitTemplate ) or...

<rabbit:template id="routingTemplate"
    connection-factory="rcf"
    send-connection-factory-selector-expression="messageProperties.headers['cfKey']" />

<bean id="rcf" class="org.springframework.amqp.rabbit.connection.SimpleRoutingConnectionFactory">
    <property name="targetConnectionFactories">
        <map>
            <entry key="foo" value-ref="cf1"/>
            <entry key="bar" value-ref="cf2"/>
        </map>
    </property>
    <property name="defaultTargetConnectionFactory" ref="defaultCF"/>
</bean>

...and then...

this.routingTemplate.convertAndSend("exchange", "routingKey", "xyz", new MessagePostProcessor() {

    @Override
    public Message postProcessMessage(Message message) throws AmqpException {
        message.getMessageProperties().setHeader("cfKey", "foo");
        return message;
    }

});

There's a complete test case here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM