有关Spring Boot主题的DLQ

时间:2017-03-23 08:41:17

标签: spring spring-boot jms activemq

我使用的是Spring Boot和ActiveMQ。我想发送和接收来自主题的消息。这很好用。我的代码如下所示:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
        JmsSpike.TestListener1.class,
        JmsSpike.TestListener2.class,
        JmsSpike.Config.class
})
@TestPropertySource(properties = {
        "spring.activemq.broker-url: tcp://localhost:61616",
        "spring.activemq.password: admin",
        "spring.activemq.user: admin",
        "spring.jms.pub-sub-domain: true", // queue vs. topic
})
@EnableJms
@EnableAutoConfiguration
public class JmsSpike {

    @Autowired
    private JmsTemplate jmsTemplate;

    @Test
    public void sendMessage() throws Exception {
        sendMessageInThread();
        Thread.sleep(10000);
    }

    private void sendMessageInThread() {
        new Thread() {
            public void run() {
                jmsTemplate.convertAndSend("asx2ras", "I'm a test");
            }
        }.start();
    }

    @TestComponent
    protected static class TestListener1 {

        @JmsListener(destination = "asx2ras")
        public void receiveMessage(String message) {
            System.out.println("****************** 1 *******************");
            System.out.println("Hey 1! I got a message: " + message);
            System.out.println("****************** 1 *******************");
        }
    }

    @TestComponent
    protected static class TestListener2 {

        @JmsListener(destination = "asx2ras")
        public void receiveMessage(String message) {
            throw new RuntimeException("Nope");
        }
    }

    @Configuration
    protected static class Config {

        @Bean
        public RedeliveryPolicy redeliveryPolicy() {
            RedeliveryPolicy topicPolicy = new RedeliveryPolicy();
            topicPolicy.setMaximumRedeliveries(1);
            return topicPolicy;
        }

        @Bean
        public ConnectionFactory connectionFactory(@Value("${spring.activemq.user}") final String username,
                                                   @Value("${spring.activemq.password}") final String password,
                                                   @Value("${spring.activemq.broker-url}") final String brokerUrl) {

            ActiveMQConnectionFactory cf = new ActiveMQConnectionFactory(username, password, brokerUrl);
            cf.setRedeliveryPolicy(redeliveryPolicy());
            return cf;
        }
    }
}
  • 我可以发送消息
  • 我收到两个听众的消息
  • 一个侦听器将始终工作并只打印一些控制台消息
  • 另一个侦听器将始终抛出异常

我将重试设置为" 1",因此在抛出异常后将再次调用失败的侦听器。但是,重试后,消息不会传递到错误队列(或错误主题)。如何将消息发送到错误队列,以便以后再次调用失败的侦听器?

请注意,我只想再次调用失败的侦听器,而不是所有关于该主题的侦听器。这可能吗?

修改

这是我的activemq.xml(仅broker标记):

<broker xmlns="http://activemq.apache.org/schema/core" brokerName="localhost" dataDirectory="${activemq.data}">

    <destinationPolicy>
        <policyMap>
          <policyEntries>
            <policyEntry topic=">" >
              <pendingMessageLimitStrategy>
                <constantPendingMessageLimitStrategy limit="1000"/>
              </pendingMessageLimitStrategy>
            </policyEntry>
          </policyEntries>
        </policyMap>
    </destinationPolicy>

    <managementContext>
        <managementContext createConnector="false"/>
    </managementContext>

    <persistenceAdapter>
        <kahaDB directory="${activemq.data}/kahadb"/>
    </persistenceAdapter>

      <systemUsage>
        <systemUsage>
            <memoryUsage>
                <memoryUsage percentOfJvmHeap="70" />
            </memoryUsage>
            <storeUsage>
                <storeUsage limit="100 gb"/>
            </storeUsage>
            <tempUsage>
                <tempUsage limit="50 gb"/>
            </tempUsage>
        </systemUsage>
    </systemUsage>

    <transportConnectors>
        <!-- DOS protection, limit concurrent connections to 1000 and frame size to 100MB -->
        <transportConnector name="openwire" uri="tcp://0.0.0.0:61616?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="amqp" uri="amqp://0.0.0.0:5672?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="stomp" uri="stomp://0.0.0.0:61613?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="mqtt" uri="mqtt://0.0.0.0:1883?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
        <transportConnector name="ws" uri="ws://0.0.0.0:61614?maximumConnections=1000&amp;wireFormat.maxFrameSize=104857600"/>
    </transportConnectors>

    <shutdownHooks>
        <bean xmlns="http://www.springframework.org/schema/beans" class="org.apache.activemq.hooks.SpringContextHook" />
    </shutdownHooks>

</broker>

1 个答案:

答案 0 :(得分:1)

根据official documentation,您可以覆盖客户端的代理配置:

  

代理传输他喜欢的默认传递策略   客户端连接在他的BrokerInfo命令包中。但客户可以   使用。覆盖策略设置   ActiveMQConnection.getRedeliveryPolicy()方法:

RedeliveryPolicy policy = connection.getRedeliveryPolicy();
policy.setInitialRedeliveryDelay(500); policy.setBackOffMultiplier(2);
policy.setUseExponentialBackOff(true);
policy.setMaximumRedeliveries(2);

因此,您配置重新传递策略的方式似乎没问题。

我看到的唯一问题是,当您创建RedeliveryPolicy的新实例并且仅设置单个字段topicPolicy.setMaximumRedeliveries(1);时,所有其他基元字段都将被分配默认值。您应该在现有的重新传递策略实例上设置最大重新传输:

RedeliveryPolicy policy = cf.getRedeliveryPolicy();
policy.setMaximumRedeliveries(1);

修改

另外,请确保使用@JmsListener未使用CLIENT_ACKNOWLEDGE。根据此thread,在使用CLIENT_ACKNOWLEDGE时,不会重新传递邮件。