处理 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
,但现在不再是这种情况了...
我们可以查看您的配置以确定发生了什么,并可能重现以引导您找到正确的解决方案吗?
我的代码故意抛出 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 的要求添加配置文件 而我的 Transformer 定义为 <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
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
,但现在不再是这种情况了...
我们可以查看您的配置以确定发生了什么,并可能重现以引导您找到正确的解决方案吗?