【问题标题】:Handle exceptions/errors other than MessagingException ie.., other error/exception which are not wrapped as MessagingException in spring-integration处理除 MessagingException 以外的异常/错误,即..,其他未在 spring-integration 中包装为 MessagingException 的错误/异常
【发布时间】:2020-10-21 04:58:45
【问题描述】:

我的代码故意抛出 SourceAssertionError。在早前的 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-integration 升级之后,我的代码流以这样一种方式进行,即错误(Not MessagingException)没有被路由到错误通道。 RequestRetryHandlerAdvice 中的 doInvoke() 抛出的异常在路由到错误通道之前被拒绝,因为逻辑要求它们是特定类型的,即,如果只有异常是 MessaginException,则将其路由到错误通道。流程退出,但 GatewayProxyFactoryBean 中的 rethrowExceptionCauseIfPossible(..) 抛出异常。在升级之前,我的错误已被包装到 MessagingException 并且流程到达 MessagingGatewaySupport 中的 handleSendAndReceiveError(..),它通常被路由到自定义定义的错误通道。升级到 5.3.2 后不会发生这种情况。随着流程在其自身之前结束而发布

我的 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;
    }

    

【问题讨论】:

  • 添加了错误通道的配置和转换器

标签: java exception error-handling spring-integration


【解决方案1】:

“回归”已通过此更改完成: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,现在情况不再如此......

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

【讨论】:

  • 我添加了配置和转换器来提问。除此之外,我调试了流程,它没有达到handleSendAndReceiveError。流程进入 this.messagingTemplate.sendAndReceive(channel, requestMessage);并在 RequestHandlerRetryAdvice 的 doInvoke() 中以 ThrowbaleHolderException 退出并到达 RetryTemplate 的 catch(Throwable) 并以 catch(ThrowableHolderException) 结束,并最终在 GatewayProxyFactoryBean 的 rethrowExceptionCauseIfPossible() 处以 originalException 作为 SourceAssertionError 进一步退出应用程序
  • 在升级之前发生的事情是我的错误被包裹在 RequestRetryHandlerAdvice 的 catch 块中的 MessagingException 中。这是因为在早期版本中没有针对 ThrowableHolderException 的 catch 语句。所以,在 5.1.6 版本中我看不到任何问题
  • 嗯。你的SourceAssertionError 不是Exception,而只是Error?这就是我们没有在MessagingGatewaySupport
  • SourceAssertionError 附加了 ThrowHolderException,经过检查,它看起来像这样 org.springframework.integration.handler.advice.AbstractRequestHandlerAdvice$ThrowableHolderException: org.springframework.ws.test.support.SourceAssertionError
  • 另外,您在解包后是正确的,这个“错误”不会在 MessagingGatewaySuport 中捕获,因为它现在是错误。我相信它不会达到 handleSendAndReceiveError
猜你喜欢
  • 2017-11-15
  • 2014-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-05
相关资源
最近更新 更多