处理 exceptions/errors 除了 MessagingException 即..,其他 error/exception 未包装为 spring-integration 中的 MessagingException

Handle exceptions/errors other than MessagingException ie.., other error/exception which are not wrapped as MessagingException in spring-integration

我的代码故意抛出 SourceAssertionError。早些时候在 spring-integraton 的 5.1.6.release 中,对于任何错误,在 RequestHandlerRetryAdvice 中,对于任何错误,它会将其包装在 MessagingException 中。在 RequestHandlerRetryAdvice 的 doInvoke() 下面,

@Override
    protected Object doInvoke(final ExecutionCallback callback, Object target, final Message<?> message)
            throws Exception {
        RetryState retryState = null;
        retryState = this.retryStateGenerator.determineRetryState(message);
        messageHolder.set(message);

        try {
            return this.retryTemplate.execute(context -> callback.cloneAndExecute(), this.recoveryCallback, retryState);
        }
        catch (MessagingException e) {
            if (e.getFailedMessage() == null) {
                throw new MessagingException(message, "Failed to invoke handler", e);
            }
            throw e;
        }
        catch (Exception e) {
            throw new MessagingException(message, "Failed to invoke handler", unwrapExceptionIfNecessary(e));
        }
        finally {
            messageHolder.remove();
        }
    }

但现在在 5.3.2.Release 中,它没有包含在 MessagingException 中,而是作为 THrowableHolderException 抛出,如下所示

@Override
    protected Object doInvoke(final ExecutionCallback callback, Object target, final Message<?> message) {
        RetryState retryState = this.retryStateGenerator.determineRetryState(message);
        MESSAGE_HOLDER.set(message);

        try {
            return this.retryTemplate.execute(context -> callback.cloneAndExecute(), this.recoveryCallback, retryState);
        }
        catch (MessagingException e) {
            if (e.getFailedMessage() == null) {
                throw new MessagingException(message, "Failed to invoke handler", e);
            }
            throw e;
        }
        catch (ThrowableHolderException e) { // NOSONAR catch and rethrow
            throw e;
        }
        catch (Exception e) {
            throw new ThrowableHolderException(e);
        }
        finally {
            MESSAGE_HOLDER.remove();
        }
    }

现在在 spring-集成升级后,我的代码流以错误(非 MessagingException)不会被路由到错误通道的方式进行。 RequestRetryHandlerAdvice 中的 doInvoke() 抛出的异常在路由到错误通道之前被拒绝,因为逻辑要求它们具有特定类型,即,如果只有异常是 MessaginException,那么它就会路由到错误通道。流程退出,异常由 GatewayProxyFactoryBean 中的 rethrowExceptionCauseIfPossible(..) 抛出。在升级之前,我的错误已被包装到 MessagingException 并且流程到达 MessagingGatewaySupport 中的 handleSendAndReceiveError(..),它通常被路由到自定义错误通道。升级到 5.3 后不会发生这种情况。2.Release 因为流程先于自身结束

我的 spring 配置非常简单,我只为网关定义了一个自定义错误通道。

现在我的问题是如何处理这个错误?无论如何我可以通过路由到任何新定义的错误通道来处理它,或者我可以通过我已经定义的 myErrorChannel 来处理它吗?

EDIT1:按照 Artem Bilan 的要求添加配置文件

    <bean id="myPreferences" class="package.MyPreferences" />
    <bean id="myExceptionTransformer"
        class="package.myExceptionTransformer" />
    <int:channel id="myErrorChannel" />
    <int:transformer input-channel="myErrorChannel"
        ref="myExceptionTransformer" />
    <bean id="Logger" class="package.Logger" />

    <int:gateway id="gateway" error-channel="myErrorChannel"
        service-interface="package.myClient"
        default-request-channel="myRoutingChannel">
        <int:method name="invokeAuthenticationRequest">
            <int:header
                name="#{T(name1)}"
                value="#{T(value1)}" />
        </int:method>
        <int:method name="invokeProvRequest">
            <int:header
                name="#{T(name2)}"
                value="#{T(value2)}" />
        </int:method>
    </int:gateway>

    <int:publish-subscribe-channel id="myRoutingChannel" />

    <int:header-value-router input-channel="myRoutingChannel"
        header-name="#{T(package.AppContext).REQUEST_TYPE}">
        <int:mapping
            value="#{T(value1)}"
            channel="authGatewayChannel" />
        <int:mapping
            value="#{T(value2)}"
            channel="provGatewayChannel" />
    </int:header-value-router>

    
        <int-ws:request-handler-advice-chain>
            <ref bean="provRetryAdvice" />
        </int-ws:request-handler-advice-chain>
    </int-ws:outbound-gateway>

    
    <bean id="provRetryAdvice"
        class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
        <property name="retryTemplate">
            <bean class="org.springframework.retry.support.RetryTemplate">
                <property name="backOffPolicy">
                    <bean class="org.springframework.retry.backoff.FixedBackOffPolicy">
                        <property name="backOffPeriod" value="4000" />
                    </bean>
                </property>
                <property name="retryPolicy">
                    <bean class="org.springframework.retry.policy.SimpleRetryPolicy">
                        <property name="maxAttempts" value="#{provisioningRetryCount.intValue()}" />
                    </bean>
                </property>
            </bean>
        </property>
    </bean> 

而我的 Transformer 定义为

@Transformer
    public Message<?> transformErrorToResponse(Message<?> exceptionMessage) {

        Object exceptionMessagePayload = exceptionMessage.getPayload();
        Throwable cause = ((MessagingException) exceptionMessagePayload).getCause();
newPayload = new myException(msg);

        /*add headers*/
        return errorMessage;
    }

    

此更改已完成“回归”:https://github.com/spring-projects/spring-integration/commit/b187bca36e2565e80e72e662c204a57c05aab11d

所以,是的,我们不再为常规异常抛出 MessagingException 包装器,以避免无意义地使用更大的堆栈跟踪。

我不完全确定您的异常如何无法到达该错误通道。 MessagingGatewaySupport中的代码是这样的:

    try {
        ...
            reply = this.messagingTemplate.sendAndReceive(channel, requestMessage);
        ...
    }
    catch (Exception ex) {
        ...
        reply = ex;
        ...
    }

    if (reply instanceof Throwable || reply instanceof ErrorMessage) {
        Throwable error =
                reply instanceof ErrorMessage
                        ? ((ErrorMessage) reply).getPayload()
                        : (Throwable) reply;
        return handleSendAndReceiveError(object, requestMessage, error, shouldConvert);
    }

可能是您的错误处理程序中的逻辑仅检查接收到的 ErrorMessage 中的 MessagingException,但现在不再是这种情况了...

我们可以查看您的配置以确定发生了什么,并可能重现以引导您找到正确的解决方案吗?