Spring JMS模板 - 并发调用

3

我可以使用Spring的JMSTemplate进行并发调用吗?

我想要同时进行4个外部服务调用,正在探索使用Spring的JMSTemplate来实现这些并行调用并等待执行完成。

另一个选择是使用ExecutorService

使用其中一个是否有优势?


你想要同时调用不同的JMS队列还是相同的队列? - Pavan
给不同的JMS队列,Pavan - Punter Vicky
你想要对外部服务器进行同步调用还是异步调用?也就是说,你想在发送请求后阻塞线程并等待响应(在服务器处理请求之前无法在该线程中执行其他操作)吗?还是希望线程在发出请求后继续执行其工作(无论是什么),同时异步等待服务器的响应? - Andrew Lygin
我扩展了我的答案,这样你就可以在两种情况下找到解决方案。 - Andrew Lygin
2个回答

5

JMSTemplate是线程安全的,因此对它进行并行调用不是问题。

对于大多数任务来说,消息服务通常足够快,并且可以以最小的延迟接收您的消息,因此添加ExecutorService似乎不是您通常需要的第一件事。您真正需要做的是正确配置JMS连接池并提供足够的开放连接(在您的情况下为四个),以便它可以处理您的并行请求而不会阻塞。

只有在您不关心保证交付并且您的程序需要极高的速度时,才需要使用ExecutorService,而您的消息服务无法提供这种速度,这种情况非常罕见。

至于从外部服务接收回复,您需要使用JMS请求/响应模式(您可以在本文中找到示例)。幸运的是,由于您正在使用Spring,您可以让Spring Integration为您完成大量工作。您需要配置outbound-gateway以发送消息和inbound-gateway以接收响应。自2.2版本以来,您还可以使用reply-listener来简化客户端方面的事情。所有这些组件都在官方文档中涵盖(也包括示例)。


谢谢 @Andrew。我能否使用JMS并等待接收到响应?过去我曾经使用JMS进行异步消息传递,但在这种情况下,我的代码应该阻塞,直到我收到所有4个调用的响应。 - Punter Vicky
关于连接池的问题,我的服务每分钟会收到数百个请求,所以我认为如果我没记错的话,应该设置一个更高的连接池。 - Punter Vicky
对于大多数现代消息系统来说,每分钟处理100个请求并不是什么大问题(如果配置正确)。而且,如果您只使用四个线程发送消息,那么就不需要更多的连接,因为它们将处于空闲状态。但是,您可能需要一些额外的连接来接收响应。让我们在评论中继续讨论您的问题,然后我将能够澄清我的答案。 - Andrew Lygin
非常好,非常感谢!在程序中是否有可能在某个特定点阻塞,而不是在请求发送后立即阻塞?通常情况下,当我使用Java的Future时,我会在需要响应继续进行的地方执行future.get。对于JMS,这种操作是否可行? - Punter Vicky
确实。您需要创建一个简单的类(我们称之为 RemoteService),其中包含一个名为 request(...) 的方法,该方法将请求发送到服务器,并创建一个 Future,然后将其放入某个本地映射(并发映射)中,以消息 ID 作为键,将此 Future 返回给调用方,然后异步等待来自服务器的响应。一旦响应到达,只需在映射中找到相应的 Future(使用响应的关联 ID),并为其分配一个值。 - Andrew Lygin

3

需要使用异步方法与两个以上的JMS队列(发送和/或接收)进行通信。最佳选择是在方法级别使用@Asynch。

此示例包含RestTemplate,但在您的情况下,请创建JmsTemplate bean。

先决条件:请创建适当的JMS Bean以连接到队列。正确使用此功能将有助于并行调用两个队列。我已经实施过,所以它肯定有效。由于版权问题,我只提供了框架代码。

更多细节:Spring Boot + Spring Asynch https://spring.io/guides/gs/async-method/

步骤1:创建一个服务类,在该类中定义JMS队列。

@EnableAsynch
public class JMSApplication {

@Autowired
JmsService jmsService;

     public void invokeMe(){
      // Start the clock
        long start = System.currentTimeMillis();

        // Kick of multiple, asynchronous lookups
        Future<Object> queue1= jmsService.findqueue1();
        Future<Object> queue2= jmsService.findqueue2();

        // Wait until they are all done
        while (!(queue1.isDone() && queue2.isDone())) {
            Thread.sleep(10); //10-millisecond pause between each check
        }

        // Print results, including elapsed time
        System.out.println("Elapsed time: " + (System.currentTimeMillis() - start));
        System.out.println(queue1.get());
        System.out.println(queue2.get());

     }
}

步骤2:编写服务方法,其中包含Jms的业务逻辑。
   @Service
   public Class JmsService{

         @Asynch
         public Object findqueue1(){
         //Logic to invoke the JMS queue 
         }

         @Asynch
         public Object findqueue2(){
         //Logic to invoke the JMS queue 
         }
    }

谢谢Pavan!我会试一下,因为我也在使用Spring Boot。 - Punter Vicky
是的,确实!再次感谢你,Pavan :) - Punter Vicky

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接