无法在 Spring 集成中将回复频道设置为消息 Header

Unable to set Reply Channel to Message Header in Spring Integration

肯定是我遗漏了什么所以在这里寻求帮助。

我正在使用 Spring 与以下 HTTP 入站网关集成构建一个简单的 REST 应用程序:

<!-- Gateway -->
    <int-http:inbound-gateway id="fruitQuotePOSTGateway"
                              request-channel="fruitQuotePOSTRequests"
                              supported-methods="POST"
                              path="/api/v1/fruit-quote"
                              request-payload-type="java.lang.String"
                              reply-timeout="10000"
                              reply-channel="fruitQuotePOSTResponses"
                              error-channel="applicationErrors">
        <int-http:request-mapping consumes="application/xml" produces="application/xml"/>
    </int-http:inbound-gateway>

一旦 XML 进入此网关,它会经历以下简单步骤:

首先,这是整个应用程序的 XML 配置(为简洁起见,省略了 HTTP 名称空间):

<!-- Gateway -->
    <int-http:inbound-gateway id="fruitQuotePOSTGateway"
                              request-channel="fruitQuotePOSTRequests"
                              supported-methods="POST"
                              path="/api/v1/fruit-quote"
                              request-payload-type="java.lang.String"
                              reply-timeout="10000"
                              reply-channel="fruitQuotePOSTResponses"
                              error-channel="applicationErrors">
        <int-http:request-mapping consumes="application/xml" produces="application/xml"/>
    </int-http:inbound-gateway>

    <!--
    - Generate fruit quote request JAXB from the incoming request
    - Create a header "requestUUID" by reading it from fruit quote request JAXB
    - Generate fruit quote acknowledgement response for the calling client
    -->

    <int:transformer input-channel="fruitQuotePOSTRequests"
               ref="fruitQuoteTransformation"
               method="generateFruitQuoteRequestJAXB"/>

    <int:header-enricher input-channel="requestUUIDEnrichment" output-channel="orderIDGeneration">
        <int:header name="requestUUID" expression="payload.getFruitQuoteRequestJAXB().getFRUITQUOTEREQUESTDATA().getUuid()"/>
    </int:header-enricher>

    <int:transformer input-channel="fruitQuoteAcknowledgementGeneration"
                     ref="fruitQuoteTransformation"
                     method="generateFruitQuoteAcknowledgement"
                     output-channel="fruitQuotePOSTResponses"/>

    <!-- Error handling -->
    <int:transformer input-channel="applicationErrors"
                     ref="fruitQuoteTransformation"
                     method="generateFruitQuoteAcknowledgementWithError"
                     output-channel="fruitQuotePOSTResponses"/>

    <!-- Channels -->
    <int:channel id="fruitQuotePOSTRequests"/>
    <int:channel id="requestUUIDEnrichment"/>
    <int:channel id="fruitQuotePOSTResponses"/>
    <int:channel id="fruitQuoteAcknowledgementGeneration"/>
    <int:channel id="applicationErrors"/>

在应用程序中从一个步骤流向另一个步骤的有效载荷是一个自定义生成器Object,如下(省略包名称):

import static java.util.Objects.nonNull;

public class FruiteQuoteComposite {
    private final FRUITQUOTEREQUEST fruitQuoteRequestJAXB;
    private final FruitQuoteApplicationException fruitQuoteApplicationException;
    private final Integer orderID;
    private final ErrorInformation errorInformation;

    private FruiteQuoteComposite(FruiteQuoteCompositeBuilder fruiteQuoteCompositeBuilder) {
        this.fruitQuoteRequestJAXB = fruiteQuoteCompositeBuilder.fruitQuoteRequestJAXB;
        this.fruitQuoteApplicationException = fruiteQuoteCompositeBuilder.fruitQuoteApplicationException;
        this.orderID = fruiteQuoteCompositeBuilder.orderID;
        this.errorInformation = fruiteQuoteCompositeBuilder.errorInformation;
    }

    public FruitQuoteApplicationException getFruitQuoteApplicationException() {
        return fruitQuoteApplicationException;
    }

    public FRUITQUOTEREQUEST getFruitQuoteRequestJAXB() {
        return fruitQuoteRequestJAXB;
    }

    public Integer getOrderID() {
        return orderID;
    }

    public ErrorInformation getErrorInformation() {
        return errorInformation;
    }

    public static class FruiteQuoteCompositeBuilder {
        private FRUITQUOTEREQUEST fruitQuoteRequestJAXB;
        private FruitQuoteApplicationException fruitQuoteApplicationException;
        private Integer orderID;
        private ErrorInformation errorInformation;

        public FruiteQuoteCompositeBuilder() {
        }

        public FruiteQuoteCompositeBuilder setFruitQuoteRequestJAXB(FRUITQUOTEREQUEST fruitQuoteRequestJAXB) {
            if (nonNull(fruitQuoteRequestJAXB)) {
                this.fruitQuoteRequestJAXB = fruitQuoteRequestJAXB;
            }

            return this;
        }

        public FruiteQuoteCompositeBuilder setFruitQuoteApplicationException(FruitQuoteApplicationException fruitQuoteApplicationException) {
            if (nonNull(fruitQuoteApplicationException)) {
                this.fruitQuoteApplicationException = fruitQuoteApplicationException;
            }

            return this;
        }

        public FruiteQuoteCompositeBuilder setOrderID(Integer orderID) {
            if(nonNull(orderID)) {
                this.orderID = orderID;
            }

            return this;
        }

        public FruiteQuoteCompositeBuilder setErrorInformation(ErrorInformation errorInformation) {
            if (nonNull( errorInformation )) {
                this.errorInformation = errorInformation;
            }
            return this;
        }

        public FruiteQuoteComposite build() {
            return new FruiteQuoteComposite(this);
        }
    }
}

我没有在转换器上使用 "output-channel" 的原因是因为我想在 java 逻辑 运行 转换中明确选择 replyChannel/outgoing 路由.

例如,在 FruitQuoteTransformation.generateFruitQuoteRequestJAXB 方法中,我为成功设置了一条路线,为 exceptions/errors 设置了另一条路线,如下所示:

public Message<FruiteQuoteComposite> generateFruitQuoteRequestJAXB(Message<String> fruitQuoteRequestMessage) {
        String fruitQuoteRequest = fruitQuoteRequestMessage.getPayload();
        Unmarshaller unmarshaller;
        FRUITQUOTEREQUEST fruitQuoteRequestJAXB;

        try {
            unmarshaller = requireNonNull(fruitQuoteRequestJaxbContext).createUnmarshaller();
            fruitQuoteRequestJAXB = (FRUITQUOTEREQUEST) requireNonNull(unmarshaller)
                    .unmarshal(new StringReader(fruitQuoteRequest));
        } catch (JAXBException jaxbException) {
            logger.error("JAXB Unmarshalling exception occurred with error code :: " + ERR_FRUIT_QUOTE_REQUEST_JAXB_TRANSFORMATION, jaxbException);
            FruitQuoteApplicationException fruitQuoteApplicationException = generateFruitQuoteApplicationException(ERR_FRUIT_QUOTE_REQUEST_JAXB_TRANSFORMATION, MESSAGE_FRUIT_QUOTE_INTERNAL_SYSTEM_ERROR);

            FruiteQuoteComposite outboundFruitQuoteComposite = new FruiteQuoteComposite.FruiteQuoteCompositeBuilder()
                    .setFruitQuoteApplicationException(fruitQuoteApplicationException)
                    .build();

            return withPayload(requireNonNull(outboundFruitQuoteComposite))
                    .setHeader(MessageHeaders.REPLY_CHANNEL, "applicationErrors")
                    .build();
        }

        FruiteQuoteComposite outboundFruitQuoteComposite = new FruiteQuoteComposite.FruiteQuoteCompositeBuilder()
                .setFruitQuoteRequestJAXB(fruitQuoteRequestJAXB)
                .build();

        return withPayload(requireNonNull(outboundFruitQuoteComposite))
                .setHeader(MessageHeaders.REPLY_CHANNEL, "requestUUIDEnrichment")
                .build();
    }

你能帮忙吗?

绝对不能乱用框架的replyChannelheader;它不用于路由目的。

replyChannel 是一个内部渠道,每条消息都是唯一的,用于关联对请求的回复。您通常不需要在入站网关上显式 reply-channel;如果这样做,它会在运行时简单地桥接到消息的 replyChannel header.

应该在网关 error-channel 上处理错误情况,而不是抛出异常。不同的异常类型可以指示不同的错误。