[英]Asynchronous RPC using Spring Boot RabbitMQ
I have implemented a basic asynchronous RPC call using spring boot 1.4 and rabbit mq. 我已经使用Spring Boot 1.4和Rabbit MQ实现了一个基本的异步RPC调用。
My intention is to use this example as a basis of communication among micro services. 我的意图是将此示例用作微服务之间通信的基础。
For example, Publisher.java and Subscriber.java could be two micro services talking to each other. 例如,Publisher.java和Subscriber.java可以是两个相互通信的微服务。
The code shown works fine, but I am curious to know if there are any better ways of doing this? 显示的代码可以正常工作,但是我很好奇是否有更好的方法可以做到这一点?
My queries as follows: 我的查询如下:
@RabbitListener
annotation , I did not had to declare directExchange()
and binding()
beans in configuration. @RabbitListener
批注来侦听请求队列,我不必在配置中声明directExchange()
和binding()
Bean。 asyncRabbitTemplate
to read response from reply queue, I had to declare directExchange()
and binding()
beans in configuration. asyncRabbitTemplate
从回复队列读取响应,我必须在配置中声明directExchange()
和binding()
Bean。 rpcReplyMessageListenerContainer()
and asyncRabbitTemplate()
for each request-reply call. rpcReplyMessageListenerContainer()
和asyncRabbitTemplate()
。 Code as follows. 代码如下。 Link to Github
链接到Github
@Configuration("asyncRPCConfig")
@Profile("async_rpc")
@EnableScheduling
@EnableRabbit
@ComponentScan(basePackages = {"in.rabbitmq.async_rpc"})
public class Config {
@Value("${queue.reply}")
private String replyQueue;
@Value("${exchange.direct}")
private String directExchange;
@Value("${routingKey.reply}")
private String replyRoutingKey;
@Bean
public Publisher publisher() {
return new Publisher();
}
@Bean
public SimpleRabbitListenerContainerFactory simpleMessageListenerContainerFactory(ConnectionFactory connectionFactory,
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
return factory;
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(jsonMessageConverter());
return template;
}
@Bean
public MessageConverter jsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
public Queue replyQueueRPC() {
return new Queue(replyQueue);
}
@Bean
public SimpleMessageListenerContainer rpcReplyMessageListenerContainer(ConnectionFactory connectionFactory) {
SimpleMessageListenerContainer simpleMessageListenerContainer = new SimpleMessageListenerContainer(connectionFactory);
simpleMessageListenerContainer.setQueues(replyQueueRPC());
simpleMessageListenerContainer.setReceiveTimeout(2000);
simpleMessageListenerContainer.setTaskExecutor(Executors.newCachedThreadPool());
return simpleMessageListenerContainer;
}
@Bean
public AsyncRabbitTemplate asyncRabbitTemplate(ConnectionFactory connectionFactory) {
return new AsyncRabbitTemplate(rabbitTemplate(connectionFactory),
rpcReplyMessageListenerContainer(connectionFactory),
directExchange + "/" + replyRoutingKey);
}
@Bean
public DirectExchange directExchange() {
return new DirectExchange(directExchange);
}
@Bean
public Binding binding() {
return BindingBuilder.bind(replyQueueRPC()).to(directExchange()).with(replyRoutingKey);
}
@Bean
public Subscriber subscriber() {
return new Subscriber();
}
}
public class Publisher {
@Value("${routingKey.request}")
private String requestRoutingKey;
@Autowired
private DirectExchange directExchange;
private static SecureRandom SECURE_RANDOM;
static {
try {
SECURE_RANDOM = SecureRandom.getInstanceStrong();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
@Autowired
private AsyncRabbitTemplate asyncRabbitTemplate;
@Scheduled(fixedDelay = 100 * 1)
public void publishToDirectExchangeRPCStyle() {
Integer integer = SECURE_RANDOM.nextInt();
SampleRequestMessage sampleRequestMessage = new SampleRequestMessage(String.valueOf(integer));
System.out.println("Sending out message on direct directExchange:" + sampleRequestMessage);
AsyncRabbitTemplate.RabbitConverterFuture<SampleResponseMessage> sampleResponseMessageRabbitConverterFuture = asyncRabbitTemplate
.convertSendAndReceive(directExchange.getName(), requestRoutingKey, sampleRequestMessage);
sampleResponseMessageRabbitConverterFuture.addCallback(
sampleResponseMessage ->
System.out.println("Response for request message:" + sampleRequestMessage + " is:" + sampleResponseMessage)
, failure ->
System.out.println(failure.getMessage())
);
}
}
public class Subscriber {
@RabbitHandler
@RabbitListener(
bindings = {
@QueueBinding(value = @Queue("${queue.request}"),
key = "${routingKey.request}",
exchange = @Exchange(value = "${exchange.direct}", type = ExchangeTypes.DIRECT, durable = "true"))})
public SampleResponseMessage subscribeToRequestQueue(@Payload SampleRequestMessage sampleRequestMessage, Message message) {
System.out.println("Received message :" + message);
return new SampleResponseMessage(sampleRequestMessage.getMessage());
}
}
Your solution is fine. 您的解决方案很好。
It is not clear what you are asking... 不清楚您在问什么...
I had to declare directExchange() and binding() beans in configuration.
我必须在配置中声明directExchange()和binding()Bean。 Is there any way I can avoid it, because I feel it is code duplication as I am declaring these beans twice.
有什么办法可以避免它,因为我感觉这是代码重复,因为我两次声明了这些bean。
@QueueBinding
is simply a convenience on @RabbitListener
and an alternative to declaring the queue, exchange and binding as @Bean
s. @QueueBinding
是简单地在一个方便@RabbitListener
并宣布该队列,交换和作为结合的替代@Bean
秒。
If you are using a common @Config
class you can simply omit the bindings
attribute on the listener and use queues = "${queue.reply}"
to avoid the duplication. 如果使用通用的
@Config
类,则可以简单地忽略侦听器上的bindings
属性,并使用queues = "${queue.reply}"
来避免重复。
I would need to declare similar rpcReplyMessageListenerContainer() and asyncRabbitTemplate() for each request-reply call.
我将需要为每个请求-应答调用声明类似的rpcReplyMessageListenerContainer()和asyncRabbitTemplate()。 Is that correct?
那是对的吗?
Yes; 是; although with the upcoming 2.0 release, you can use a
DirectReplyToMessageListenerContainer
which avoids the need for a separate reply queue for each service; 尽管在即将发布的2.0版本中,您可以使用
DirectReplyToMessageListenerContainer
,从而避免了每个服务都需要单独的回复队列的DirectReplyToMessageListenerContainer
; when you send a message. 当您发送消息时。
See the documentation here and here . 请在此处和此处 查看文档 。
Starting with version 2.0, the async template now supports Direct reply-to instead of a configured reply queue.
从2.0版开始,异步模板现在支持直接答复而不是配置的答复队列。
(Should read "as an alternative to " rather than "instead of"). (应读为“替代”而不是“代替”)。
So you can use the same template to talk to multiple services. 因此,您可以使用同一模板与多个服务进行通话。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.