Java 更新:IBM MQ系列上的Spring Boot JMS静态回复队列
在我的用例中,我需要通过托管队列对远程系统进行请求-应答呼叫。使用springboot和IBM的mqstarter,我遇到了一个问题:应用程序希望创建动态/临时应答队列,而不是使用已经存在的托管队列 配置是在这里设置的Java 更新:IBM MQ系列上的Spring Boot JMS静态回复队列,java,spring-boot,spring-integration,ibm-mq,spring-jms,Java,Spring Boot,Spring Integration,Ibm Mq,Spring Jms,在我的用例中,我需要通过托管队列对远程系统进行请求-应答呼叫。使用springboot和IBM的mqstarter,我遇到了一个问题:应用程序希望创建动态/临时应答队列,而不是使用已经存在的托管队列 配置是在这里设置的 @EnableJms @Configuration public class QueueConfiguration { @Bean public MQQueueConnectionFactory connectionFactory() throws JMSExcepti
@EnableJms
@Configuration
public class QueueConfiguration {
@Bean
public MQQueueConnectionFactory connectionFactory() throws JMSException {
MQQueueConnectionFactory factory = new MQQueueConnectionFactory();
factory.setTransportType(CT_WMQ); // is 1
factory.setHostName(queueProperties.getHost());
factory.setPort(queueProperties.getPort());
factory.setChannel(queueProperties.getChannel()); // combo of ${queueManager}%${channel}
return factory;
}
@Bean
public JmsMessagingTemplate messagingTemplate(ConnectionFactory connectionFactory) {
JmsMessagingTemplate jmt = new JmsMessagingTemplate(connectionFactory);
jmt.setDefaultDestinationName(queueProperties.getQueueName());
return jmt;
}
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setPackagesToScan("com.foo.model");
return marshaller;
}
@Bean
public MessageConverter messageConverter(Jaxb2Marshaller marshaller) {
MarshallingMessageConverter converter = new MarshallingMessageConverter();
converter.setMarshaller(marshaller);
converter.setUnmarshaller(marshaller);
return converter;
}
}
用法非常简单:将对象转换并发送。等待响应接收
并转换它
@Component
public class ExampleSenderReceiver {
@Autowired
private JmsMessagingTemplate jmsMessagingTemplate;
@Override
@SneakyThrows
public ResponseExample sendAndReceive(RequestExample request, String correlationId) {
MessagePostProcessor mpp = message -> {
message = MessageBuilder.fromMessage(message)
.setHeader(JmsHeaders.CORRELATION_ID, correlationId)
// .setHeader(JmsHeaders.REPLY_TO, "DEV.QUEUE.3") this triggers queue creation
.build();
return message;
};
String destination = Objects.requireNonNull(jmsMessagingTemplate.getDefaultDestinationName());
return jmsMessagingTemplate.convertSendAndReceive(destination, request, ResponseExample.class, mpp);
}
我已经阅读了大量IBM文档,并认为需要将设置为“MQMT_请求”,但我没有找到正确的位置
更新
添加了Spring集成,并添加了JmsOutboundGateway的配置
@Bean
public MessageChannel requestChannel() {
return new DirectChannel();
}
@Bean
public QueueChannel responseChannel() {
return new QueueChannel();
}
@Bean
@ServiceActivator(inputChannel = "requestChannel" )
public JmsOutboundGateway jmsOutboundGateway( ConnectionFactory connectionFactory) {
JmsOutboundGateway gateway = new JmsOutboundGateway();
gateway.setConnectionFactory(connectionFactory);
gateway.setRequestDestinationName("REQUEST");
gateway.setReplyDestinationName("RESPONSE");
gateway.setReplyChannel(responseChannel());
gateway.setCorrelationKey("JMSCorrelationID*");
gateway.setIdleReplyContainerTimeout(2, TimeUnit.SECONDS);
return gateway;
}
并改编了我的示例SenderReceiver类
@Autowired
@Qualifier("requestChannel")
private MessageChannel requestChannel;
@Autowired
@Qualifier("responseChannel")
private QueueChannel responseChannel;
@Override
@SneakyThrows
public ResponseExample sendAndReceive(RequestExample request, String correlationId) {
String xmlContent = "the marshalled request object";
Map<String, Object> header = new HashMap<>();
header.put(JmsHeaders.CORRELATION_ID, correlationId);
GenericMessage<String> message1 = new GenericMessage<>(xmlContent, header);
requestChannel.send(message1);
log.info("send done" );
Message<?> receive = responseChannel.receive(1500);
if(null != receive){
log.info("incoming: {}", receive.toString());
}
}
@Autowired
@限定符(“请求通道”)
私有消息通道请求通道;
@自动连线
@限定符(“响应通道”)
专用队列通道响应通道;
@凌驾
@鬼鬼祟祟
公共响应示例发送和接收(请求示例请求,字符串关联ID){
String xmlContent=“已封送的请求对象”;
Map header=newhashmap();
header.put(JmsHeaders.CORRELATION_ID,correlationId);
GenericMessage1=新的GenericMessage(xmlContent,标头);
requestChannel.send(message1);
日志信息(“发送完成”);
消息接收=响应通道接收(1500);
如果(null!=接收){
log.info(“传入:{}”,receive.toString());
}
}
重要的部分是gateway.setCorrelationKey(“JMSCorrelationID*”)
没有该行,correlationId的传播就不正确
下一步是重新添加MessageConverters并使其再次变得漂亮
谢谢。您缺少队列管理器
ibm:
mq:
queueManager: QM1
channel: chanel
connName: localhost(1414)
user: admin
password: admin
默认JmsTemplate(由jmsMessageTemplate
使用)始终使用临时应答队列。您可以将其子类化并覆盖dosendandereceive(会话会话、目标、MessageCreator MessageCreator)
以使用托管队列
但是,只有在一次有一个未完成的请求(例如,所有请求都在一个线程上运行)时,它才会起作用。您还必须通过检查相关id来添加丢弃“延迟”到达的代码
您可以改为使用异步发送,在侦听器容器上处理回复,并将回复与请求关联起来
考虑改用springintegrationjms
及其出站网关-它在应答队列处理方面具有更大的灵活性(并为您提供所有相关功能)
队列管理器是通道属性的一部分,我在后面的注释中写了它。另一种方法是在jmsTemplate上使用
send
,而不是send和receive
。记住在发送邮件时将REPLY_设置为。然后,您可以在回复队列上设置一个常规的侦听器。这是另一个最初的想法,但随后需要缓存调用的上下文,并且必须手动关联响应。还需要只收集属于请求的响应,因此网关的动态消息选择器非常适合这个用例。我想您可能需要使用消息头。请求添加消息头设置,响应者将消息头设置添加到回复中,侦听器在消息头设置上使用选择器。