简体   繁体   中英

Web service putting Soap message in queue with Spring Integration and Jms

I want to use Spring Integration to expose a simple web service that pushes incoming message into ActiveMQ and responds immediately. My go-to solution was MarshallingWebServiceInboundGateway connected to Jms.outboundAdapter with IntegrationFlow. Below the Gateway and IntegrationFlow snippets. Problem with this is Adapter does not provide response (duh) which Gateway expects. The response I get back from the service is empty 202, with delay of about 1500ms. This is caused by a reply timeout I see in TRACE logs:

"2020-04-14 17:17:50.101 TRACE 26524 --- [nio-8080-exec-6] o.s.integration.core.MessagingTemplate   : Failed to receive message from channel 'org.springframework.messaging.core.GenericMessagingTemplate$TemporaryReplyChannel@518ffd27' within timeout: 1000" 

No hard exceptions anywhere. The other problem is I cannot generate the response myself. I can't add anything to IntegrationFlow after the.handle with Adapter.

  1. Any other way I can try to fulfill the scenario?
  2. How, if at all possible, can I generate and return response in situation there is no better approach?

Most likely the proper way would be to use Gateways on both ends, but this is not possible. I cannot wait with response until message in the queue gets consumed and processed.

'''

@Bean
public MarshallingWebServiceInboundGateway greetingWebServiceInboundGateway() {
    MarshallingWebServiceInboundGateway inboundGateway = new MarshallingWebServiceInboundGateway(
            jaxb2Marshaller()
    );
    inboundGateway.setRequestChannelName("greetingAsync.input");
    inboundGateway.setLoggingEnabled(true);
    return inboundGateway;
}

@Bean
public IntegrationFlow greetingAsync() {
    return f -> f
            .log(LoggingHandler.Level.INFO)
            .handle(Jms.outboundAdapter(this.jmsConnectionFactory)
                    .configureJmsTemplate(c -> {
                        c.jmsMessageConverter(new MarshallingMessageConverter(jaxb2Marshaller()));
                    })
                    .destination(JmsConfig.HELLO_WORLD_QUEUE));

}

'''

The logic and assumptions are fully correct: you can't return after one-way handle() and similar to that Jms.outboundAdapter() .

But your problem that you fully miss one of the first-class citizens in Spring Integration - a MessageChannel . It is important to understand that even in the flow like yours there are channels between endpoints (DSL methods) - implicit ( DirectChannel ), like in your case, or explicit: when you use a channel() in between and can place there any possible implementation: https://docs.spring.io/spring-integration/docs/5.3.0.M4/reference/html/dsl.html#java-dsl-channels

One of the crucial channel implementation is a PublishSubscribeChannel (a topic in JMS specification) when you can send the same message to several subscribed endpoints: https://docs.spring.io/spring-integration/docs/5.3.0.M4/reference/html/core.html#channel-implementations-publishsubscribechannel

In your case the fists subscriber should be your existing, one-way Jms.outboundAdapter() . And another something what is going to generate response and reply it into a replyChannel header.

For this purpose Java DSL provides a nice hook via sub-flows configuration: https://docs.spring.io/spring-integration/docs/5.3.0.M4/reference/html/dsl.html#java-dsl-subflows

So, some sample of publish-subscriber could be like this:

.publishSubscribeChannel(c -> c
                        .subscribe(sf -> sf
                                  .handle(Jms.outboundAdapter(this.jmsConnectionFactory))))
.handle([PRODUCE_RESPONSE])

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM