Spring boot - 与单独的服务共享嵌入式 JMS 代理

2023-12-02

我有两个服务应该通过 ActiveMQ 相互通信。当我将接收器和发送器放在一个服务中时,一切都运行良好,但是当我将它们分开时,我遇到了一个奇怪的 activemq 异常。

这是服务A的配置:

@EnableScheduling
@SpringBootApplication
@EnableJms
public class App extends SpringBootServletInitializer {

  private static final Logger log = LoggerFactory.getLogger(App.class);

  @Autowired
  private static JmsTemplate jms;

  public static void main(String[] args) {
    SpringApplication.run(App.class, args);
  }

}

发送消息:

  @Autowired
  private JmsTemplate jms;

  public void sendTicket(Reservation reservation) {
    log.debug("---------------sending message----------------");
    // Send a message
    jms.send("mailbox-destination", new MessageCreator() {
      public ObjectMessage createMessage(Session session) throws JMSException {
        ObjectMessage message = session.createObjectMessage();
        message.setObject(reservation);
        return message;
      }
    });
  }

JMS 配置为内存队列:

spring.activemq.in-memory=true
spring.activemq.pooled=false

服务 B 类似,但 id 没有定义 JmsContainerFactory。它只有接收器:

@Component
public class Receiver {

  private static final Logger log = LoggerFactory.getLogger(Receiver.class);

  /**
   * Receive a message with reservation and print it out as a e-ticket.
   * 
   * @param reservation
   */
  @JmsListener(destination = "mailbox-destination")
  public void receiveMessage(Reservation reservation) {
    log.info("Received <" + reservation.getId() + ">");
  }
}

服务 A 将 JMS 和 ActiveMQ 代理作为 Maven 依赖项:

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

        <dependency>
            <groupId>org.apache.activemq</groupId>
            <artifactId>activemq-broker</artifactId>
        </dependency>

服务 B 仅具有 JMS 依赖性。

您能否给我一个提示,如何在两个服务之间共享 bean 并在它们之间发送消息?我对这个话题完全陌生。

收到消息时出现以下异常

org.springframework.jms.UncategorizedJmsException: Uncategorized exception occured during JMS processing; nested exception is javax.jms.JMSException: Could not create Transport. Reason: javax.management.InstanceAlreadyExistsException: org.apache.activemq:type=Broker,brokerName=localhost

编辑:如果我从其中一项服务中删除代理依赖项,Tomcat 甚至不会启动:

java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:192)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:917)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:439)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:769)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:625)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:351)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:485)
Caused by: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[localhost]]
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:154)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1409)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1399)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: org.apache.catalina.LifecycleException: A child container failed during start
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:925)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:871)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    ... 6 common frames omitted

JMS 服务器历史上是单独部署的独立应用程序,消息的使用者和侦听器与该服务器进行通信。因此,JMS 方程中通常存在三个独立的应用程序。

现在,Spring Boot 允许将 Active MQ JMS 代理(JMS 服务器)嵌入到您的 Spring Boot 应用程序中。但是,如果您为每个 Spring Boot 服务配置其自己的嵌入式 JMS 代理,则这两个 JMS 代理是完全独立的,彼此不了解并且不以任何方式连接。

如果您想在生产中使用 JMS,明智的做法是避免使用 Spring Boot 嵌入式 JMS 代理并单独托管它。因此,对于 PROD,3 节点设置是首选。

Edit:

我怀疑我以前共享嵌入式 JMS 代理的方式是错误的。查看 Spring 文档,ActiveMQ 似乎不可能:

spring.activemq.broker-url= #ActiveMQ代理的URL。 默认自动生成。例如tcp://localhost:61616

spring.activemq.in-memory=true # 指定是否默认代理 URL 应该在记忆中。如果已指定显式代理,则忽略。

我在工作时正在尝试使用 HornetQ这些 Spring Enterprise 示例,但我现在找不到这样的配置。所以我打赌我遇到了问题并最终使用了单独的第三个节点。

如果你想进一步尝试, 我会

  1. 切换到 HornetQ 或 Artemis
  2. 从服务 B 中删除代理依赖项,只保留 spring-jms 依赖项(这样就只有 JMS 客户端依赖项可用)
  3. 尝试使用这些 HornetQ 属性来尝试拥有通过端口公开的嵌入式实例:

    spring.hornetq.mode=embedded
    spring.hornetq.port=5445
    

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

我怀疑嵌入式 Spring Boot JMS 代理背后的想法是仅允许本地内存集成测试,而不是向外界公开嵌入式 JMS 代理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring boot - 与单独的服务共享嵌入式 JMS 代理 的相关文章

随机推荐