当两个应用程序都使用嵌入式activemq时,如何将Jms消息从一个spring-boot应用程序发送到另一个应用程序

Posted

技术标签:

【中文标题】当两个应用程序都使用嵌入式activemq时,如何将Jms消息从一个spring-boot应用程序发送到另一个应用程序【英文标题】:How to send Jms message from one spring-boot application to another when both apps use embedded activemq 【发布时间】:2017-05-13 03:33:45 【问题描述】:

我有两个 spring-boot 应用程序。在接收器应用程序的 Application.java 我有:

@Bean
public JmsListenerContainerFactory<?> myFactory(ConnectionFactory connectionFactory, DefaultJmsListenerContainerFactoryConfigurer configurer) 
    DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
    configurer.configure(factory, connectionFactory);
    return factory;

在 Receiver.java ...

@JmsListener(destination = "myQueue", containerFactory = "myFactory")
public void receiveMessage(String tradeString) throws JSONException, IOException 
    tradeImpl = new ObjectMapper().readValue(tradeString, TradeImpl.class);

在发件人应用程序中,我只是使用:

public void send(trade) 
   String queueName = "myQueue";
   String tradeString = new ObjectMapper().writeValueAsString(trade);
   jmsTemplate.convertAndSend(queueName, tradeString);

所以我只是将消息发送到接收者应用程序中指定的队列名称。 我在日志中得到以下信息

无法启动 JMX 连接器无法绑定到 URL [rmi://localhost:1099>/jmxrmi]:javax.naming.NameAlreadyBoundException:jmxrmi [根异常是 java.rmi.AlreadyBoundException:

我已经阅读了以下帖子,并没有发现它非常鼓舞人心:

Spring boot - sharing embedded JMS broker with separate service

结尾是:

但正如我所提到的,我之前没有让这个工作,并且不确定它是否可能。在 Spring Boot 文档中没有找到明确的消息,它在这种组合中不起作用。

我怀疑嵌入式 Spring Boot JMS 代理背后的想法是只允许本地内存集成测试,而不是将嵌入式 JMS 代理暴露给外界。

有人知道我想做的事是否真的可行吗?如果没有,关于如何使用嵌入式代理在 Spring-boot 应用程序之间实现消息传递有什么建议吗?

【问题讨论】:

如果您有 2 个 Spring Boot 应用程序并嵌入了 ActiveMQ,这意味着 AMQ 嵌入在两个 Spring 应用程序之一中,不是吗?为什么不使用外部独立 AMQ? 我可以这样做,但我想我会在最后的手段下这样做!我真的很想知道是否有办法使用嵌入式路由在应用程序之间发送消息!我当然没有嫁给 AMQ,所以我对其他嵌入式解决方案持开放态度。 【参考方案1】:

如果您的 2 个 Spring Boot 应用程序位于同一个 jvm 上,您只需仅添加两者之一的 application.properties:

spring.activemq.broker-url=vm://localhost

Spring Boot 检测到的时候也可以配置一个 ConnectionFactory ActiveMQ 在类路径上可用。如果经纪人在场, 嵌入式代理会自动启动和配置(只要 没有通过配置指定代理 URL)。

如果您的 2 个 Spring Boot 应用程序位于 2 个不同的 jvm 上: 在一个 Spring Boot 应用程序中,您需要:

在 pom.xml 中

    <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-activemq -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-activemq</artifactId>
        <version>1.4.3.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jms</artifactId>
    </dependency>

在第二个:

在 application.properties 中

spring.activemq.broker-url=tcp://localhost:61616

在 pom.xml 中

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jms</artifactId>
</dependency>

如果你有 2 个 jvm,每个应用 1 个,默认情况下 spring boot 将只配置 vm 连接器,在第一个应用程序中你需要像这样添加 tcp 连接器:

@Bean(initMethod = "start", destroyMethod = "stop")
public BrokerService broker() throws Exception 
    final BrokerService broker = new BrokerService();
    broker.addConnector("tcp://localhost:61616");
    broker.addConnector("vm://localhost");
    broker.setPersistent(false);
    return broker;

【讨论】:

【参考方案2】:

尝试为producer 应用程序指定spring.activemq.brokerUrl=tcp://localhost:61616

这样一个嵌入式 ActiveMQ 代理将被禁用,并且将执行到另一个在 61616 端口上启动的连接。

【讨论】:

已添加,但应用程序现在响应:JMS 处理期间发生未分类异常;嵌套异常是 javax.jms.JMSException:无法连接到代理 URL:tcp://localhost:61616。原因:java.net.ConnectException:连接被拒绝”,我是否也需要在我的消费者的 application.properties 中添加任何内容? 是的...看起来broker.addConnector( "tcp://localhost:61616" ); broker.addConnector("vm://localhost:0"); 应该在那里。请参阅有关此问题的另一个答案。 VMTransportFactory 不会公开port 来收听。

以上是关于当两个应用程序都使用嵌入式activemq时,如何将Jms消息从一个spring-boot应用程序发送到另一个应用程序的主要内容,如果未能解决你的问题,请参考以下文章

ActiveMQ NMS:当代理关闭时,connection.start() 使用故障转移协议挂起

如何使用 Spring 嵌入式 ActiveMQ 代理指定自定义 activemq.xml?

使用 spring 集成自动配置 ActiveMQ

如何使用 Spring Boot 配置嵌入式 ActiveMQ 代理 URL

如何从 MQTT 生产并在 ActiveMQ 中作为 MQTT 和 JMS 消费

如何在 ActiveMq 嵌入式代理上启用 Web 控制台