配置消息代理服务器-AmqpAdmin

配置消息代理服务器-AmqpAdmin

    AMQP规范描述了在消息代理中如何利用协议来配置队列,交换和绑定。这些操作可以使用org.springframework.amqp.core package中的AmqpAdmin接口来完成,这些操作从0.8版本规范到现在为止是通用的。
     AmqpAdmin接口是基于Spring AMQP高度抽象的:
   
   
  1. public interfaceAmqpAdmin {
  2. // Exchange Operations
  3. void declareExchange(Exchange exchange);
  4. void deleteExchange(String exchangeName);
  5. // Queue Operations
  6. Queue declareQueue();
  7. String declareQueue(Queue queue);
  8. void deleteQueue(String queueName);
  9. void deleteQueue(String queueName, booleanunused, booleanempty);
  10. void purgeQueue(String queueName, booleannoWait);
  11. // Binding Operations
  12. void declareBinding(Binding binding);
  13. void removeBinding(Binding binding);
  14. Properties getQueueProperties(String queueName);
  15. }
    无参方法declareQueue()在代理商定义队列,这个队列的名称是自动生成的。自动生成的队列的附件属性还有exclusive=true,autoDelete=true,durable=false。
     declareQueue(Queue queue)接收Queue对象作为参数,并且返回queue的名称。如果你想让代理生成名称,这很有帮助。这和AnonymousQueue行车对比,它将生成UUID名称,并且设置exclusive和autoDelete属性为true。如果提供的队列的名称是空的,那么代理在声明队列的时候会生成名称,并且将名称返回给调用者。Queue自身并没有变化。这个方法只能通过RabbitAdmin编码直接调用。它不支持在应用程序上下文中自动生成。使用<rabbit:queue/>name属性设置为空或者不设置会创建AnonymousQueue。这是因为如果连接失败,重新声明的名称将会不一样。所以声明的名称应该固定,因为它们会在上下文的任何地方使用,例如,监听器:
   
   
  1. <rabbit:listener-container>
  2. <rabbit:listener ref="listener" queue-names="#{someQueue.name}"/>
  3. </rabbit:listener-container>
    RabbitMQ对AmqpAdmin的实现是RabbitAdmin,使用XML配置如下:
   
   
  1. <rabbit:connection-factory id="connectionFactory"/>
  2. <rabbit:admin id="amqpAdmin" connection-factory="connectionFactory"/>
    当CachingConnectionFactory的缓存模式是CHANNEL,RabbitAdmin的实现将自动迟声明在一个应用上下文的Queues,Exchanges,Bindings。这些组件将在打开与消息代理的连接时声明。有一些方便的命名空间,使得这些变得很方便:  
  
  
  1. <rabbit:queue id="tradeQueue"/>
  2. <rabbit:queue id="marketDataQueue"/>
  3. <fanout-exchange name="broadcast.responses"
  4. xmlns="http://www.springframework.org/schema/rabbit">
  5. <bindings>
  6. <binding queue="tradeQueue"/>
  7. </bindings>
  8. </fanout-exchange>
  9. <topic-exchange name="app.stock.marketdata"
  10. xmlns="http://www.springframework.org/schema/rabbit">
  11. <bindings>
  12. <binding queue="marketDataQueue" pattern="${stocks.quote.pattern}"/>
  13. </bindings>
  14. </topic-exchange>
    在上面的这个例子中,我们使用了匿名队列(实质上是框架帮我们生成队列的名称,而不是代理),通过引用来引用它们。当然我们可以在声明队列的时候指定队列的名称,当然这个名称同样作为引用这些bean的标识。例如:
   
   
  1. <rabbit:queue name="stocks.trade.queue"/>
提示:
    你可以同时提供id和name属性,这样你可以通过id引用这个队列。它同样允许一些标准的Spring特色,例如属性占位符或者SpEL作为Queue的name;这些属性在使用name作为标识符时候不可用。
    队列还可以配置一些额外的参数,例如x-message-ttl,x-ha-policy。使用命名空间的支持它们可以通过使用<rabbit:queue-arguments>元素以键值对的方式提供:
  
  
  1. <rabbit:queue name="withArguments">
  2. <rabbit:queue-arguments>
  3. <entry key="x-ha-policy" value="all"/>
  4. </rabbit:queue-arguments>
  5. </rabbit:queue>
    在默认的情况下,参数类型默认为字符串。对于其他的类型,我们需要提供类型信息。
   
   
  1. <rabbit:queue name="withArguments">
  2. <rabbit:queue-arguments value-type="java.lang.Long">
  3. <entry key="x-message-ttl" value="100"/>
  4. </rabbit:queue-arguments>
  5. </rabbit:queue>
    对于混合类型,我们需要为每一个entry提供:
   
   
  1. <rabbit:queue name="withArguments">
  2. <rabbit:queue-arguments>
  3. <entry key="x-message-ttl">
  4. <value type="java.lang.Long">100</value>
  5. </entry>
  6. <entry key="x-ha-policy" value="all"/>
  7. </rabbit:queue-arguments>
  8. </rabbit:queue>
    在Spring Framework3.2之后,它可以声明的更为简洁:
   
   
  1. <rabbit:queue name="withArguments">
  2. <rabbit:queue-arguments>
  3. <entry key="x-message-ttl" value="100" value-type="java.lang.Long"/>
  4. <entry key="x-ha-policy" value="all"/>
  5. </rabbit:queue-arguments>
  6. </rabbit:queue>
重点:
    RabbitMQ代理不允许声明参数不一致的队列。例如,如果一个队列已经存在,没有time to live 参数,紧接着你又试图去使用下列参数去声明一个队列 key="x-message-ttl" value="100",将会有异常抛出。
    默认的情况下,RabbitAdmin会立马停止处理所有的声明,如果有异常出现。这样将引起连锁反应,例如监听容器因为队列没有声明而导致初始化失败。
    这个问题可以通过设置RabbitAdmin的ignore-declaration-failures为true来完成。这一设置将会导致RabbitAdmin记录异常,并且继续声明其他的元素。
    自从1.3版本开始,可以配置HeaderExchange...(没明白它的作用)
   
   
  1. <rabbit:headers-exchange name="headers-test">
  2. <rabbit:bindings>
  3. <rabbit:binding queue="bucket">
  4. <rabbit:binding-arguments>
  5. <entry key="foo" value="bar"/>
  6. <entry key="baz" value="qux"/>
  7. <entry key="x-match" value="all"/>
  8. </rabbit:binding-arguments>
  9. </rabbit:binding>
  10. </rabbit:bindings>
  11. </rabbit:headers-exchange>
    如何通过Java来配置AMQP框架,看看下面的例子,使用@Configuration类AbstractStockRabbitConfiguration,它有RabbitClientConfiguration和RabbitServerConfiguration两个子类。 AbstractStockRabbitConfiguration的代码如下:
   
   
  1. @Configuration
  2. public abstract class AbstractStockAppRabbitConfiguration {
  3. @Bean
  4. public ConnectionFactory connectionFactory() {
  5. CachingConnectionFactory connectionFactory =
  6. newCachingConnectionFactory("localhost");
  7. connectionFactory.setUsername("guest");
  8. connectionFactory.setPassword("guest");
  9. returnconnectionFactory;
  10. }
  11. @Bean
  12. public RabbitTemplate rabbitTemplate() {
  13. RabbitTemplate template = newRabbitTemplate(connectionFactory());
  14. template.setMessageConverter(jsonMessageConverter());
  15. configureRabbitTemplate(template);
  16. returntemplate;
  17. }
  18. @Bean
  19. public MessageConverter jsonMessageConverter() {
  20. return newJsonMessageConverter();
  21. }
  22. @Bean
  23. public TopicExchange marketDataExchange() {
  24. return newTopicExchange("app.stock.marketdata");
  25. }
  26. // additional code omitted for brevity
  27. }
    在这个例子中,Server的配置如下:
   
   
  1. @Configuration
  2. public class RabbitServerConfiguration extends AbstractStockAppRabbitConfiguration {
  3. @Bean
  4. public Queue stockRequestQueue() {
  5. return new Queue("app.stock.request");
  6. }
  7. }
    这是@Configuration类继承链的最末端。最末端结果是当应用启动的时候TopicExchange和Queue将被声明。在Server的配置中没有绑定TopicExchange和Queue,这些将在客户端应用中做。这里队列被绑定到默认的Exchange,这种定义是规范中定义的。
    客户端的配置稍微复杂一些:
   
   
  1. @Configuration
  2. public class RabbitClientConfiguration extends AbstractStockAppRabbitConfiguration {
  3. @Value("${stocks.quote.pattern}")
  4. private String marketDataRoutingKey;
  5. @Bean
  6. public Queue marketDataQueue() {
  7. return amqpAdmin().declareQueue();
  8. }
  9. /**
  10. * Binds to the market data exchange. Interested in any stock quotes
  11. * that match its routing key.
  12. */
  13. @Bean
  14. public Binding marketDataBinding() {
  15. return BindingBuilder.bind(
  16. marketDataQueue()).to(marketDataExchange()).with(marketDataRoutingKey);
  17. }
  18. // additional code omitted for brevity
  19. }

条件声明

    默认情况下,queues,exchanges和bindings通过RabbitAdmin实例进行声明,RabbitAdmin实例随着应用上下文的启动创建。
注意:
    自从1.2版本发以来,条件声明这些元素成为可能。当一个应用连接到多个代理的时候,这会特别有用,你需要指明你要声明元素的代理。
    实现Declarable接口的类,代表着这些元素,它提供了两个方法:shouldDeclare()和getDeclaringAdmins()。RabbitAdmin使用这些方法来决定一个实例是否应该在当前连接上处理声明。
    这些属性可以在命名空间中进行配置。
   
   
  1. <rabbit:admin id="admin1" connection-factory="CF1"/>
  2. <rabbit:admin id="admin2" connection-factory="CF2"/>
  3. <rabbit:queue id="declaredByBothAdminsImplicitly"/>
  4. <rabbit:queue id="declaredByBothAdmins" declared-by="admin1, admin2"/>
  5. <rabbit:queue id="declaredByAdmin1Only" declared-by="admin1"/>
  6. <rabbit:queue id="notDeclaredByAny" auto-declare="false"/>
  7. <rabbit:direct-exchange name="direct" declared-by="admin1, admin2">
  8. <rabbit:bindings>
  9. <rabbit:binding key="foo" queue="bar"/>
  10. </rabbit:bindings>
  11. </rabbit:direct-exchange>
    注意,auto-declare属性默认情况下为true,如果declare-by属性没有提供,那么所有的RabbitAdmin都将声明这个实体。
    同样,可以基于@Configuration进行配置。
   
   
  1. @Bean
  2. public RabbitAdmin admin() {
  3. RabbitAdmin rabbitAdmin = newRabbitAdmin(cf1());
  4. rabbitAdmin.afterPropertiesSet();
  5. returnrabbitAdmin;
  6. }
  7. @Bean
  8. public RabbitAdmin admin2() {
  9. RabbitAdmin rabbitAdmin = newRabbitAdmin(cf2());
  10. rabbitAdmin.afterPropertiesSet();
  11. returnrabbitAdmin;
  12. }
  13. @Bean
  14. public Queue queue() {
  15. Queue queue = newQueue("foo");
  16. queue.setAdminsThatShouldDeclare(admin());
  17. returnqueue;
  18. }
  19. @Bean
  20. public Exchange exchange() {
  21. DirectExchange exchange = newDirectExchange("bar");
  22. exchange.setAdminsThatShouldDeclare(admin());
  23. returnexchange;
  24. }
  25. @Bean
  26. public Binding binding() {
  27. Binding binding = newBinding("foo", DestinationType.QUEUE, exchange().getName(), "foo",
  28. null);
  29. binding.setAdminsThatShouldDeclare(admin());
  30. returnbinding;
  31. }























评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值