问题
I've the understanding that Spring Integration (SI) will wrap any exception (under the SI domain) to a MessageException instance and place it on the "error-channel".
Following are few snippets from my spring config file :
<int:channel-interceptor pattern="ersServiceReqRcvPostValidationChannel,ersServiceResRcvPostValidationChannel" order="1">
<bean class="com.bnym.ecs.report.service.orchestration.interceptors.MsgJSONSyntaxValidationInterceptor"/>
</int:channel-interceptor>
<int:channel-interceptor pattern="ersServiceReqRcvPostValidationChannel,ersServiceResRcvPostValidationChannel" order="2">
<bean class="com.bnym.ecs.report.service.orchestration.interceptors.MsgMetaDataValidationInterceptor"/>
</int:channel-interceptor>
<!-- Gateways -->
<int:gateway id="ersServiceReqRcvGateway"
service-interface="com.bnym.ecs.report.service.orchestration.gateway.ERSOrchestrationSvcReqGateway"
error-channel="reqRcvExceptionHandlerChannel">
<int:method name="processRequest" request-channel="ersServiceReqRcvPostValidationChannel" />
</int:gateway>
<!-- Chain to handle all incoming request *after* doing all validations -->
<int:chain input-channel="ersServiceReqRcvPostValidationChannel">
<int:service-activator ref="msgReqAuditDetailDAOIntegrator" method="persist" />
<!-- Router -->
<int:router ref="ersServiceReqRcvRouter" />
</int:chain>
<!-- 6) Pass the message through ERS svc to Exec svc ADH chain - Chain2 -->
<int:chain input-channel="ersSvc2execSvcQMRChannel" output-channel="ersServiceResRcvPostValidationChannel">
<int:transformer ref="json2ObjTransformer" method="transformToERSOrchestrationSvcReq" />
<int:service-activator ref="executionSvcReqMsgBuilder" method="getRptExecutionSvcReqForDataEngine" />
<int:transformer ref="obj2JsonTransformer" method="transformFromRptExecutionSvcReqForDataEngine" />
<int:service-activator ref="msgReqAuditDAOIntegrator" method="persist" />
<int:service-activator ref="msgReqAuditDetailDAOIntegrator" method="persist" />
<int:service-activator ref="executionSvcRESTStub" method="executeReportJSON" />
</int:chain>
<int:chain input-channel="reqRcvExceptionHandlerChannel">
<int:transformer ref="exceptionTransformer" method="handleError"/>
</int:chain>
The client makes a REST call to my implementation class which inturn places the received request on the Gateway defined in above spring config file
@Path("/reportExecutor")
public class ERSOrchestrationServiceImpl {
@Autowired
private ReportInstanceDAO reportInstanceDAO;
private static final ERSOrchestrationSvcDiagnosticLogger _logger =
ERSOrchestrationSvcDiagnosticLogger.getInstance(ERSOrchestrationServiceImpl.class);
@Context
HttpServletRequest request;
@Context
HttpServletResponse response;
@POST
@Path("/executeOnlineReport")
@Produces({MediaType.APPLICATION_JSON})
public String executeOnlineReport(String jsonRequest) {
ApplicationContext appCtx = SpringApplicationContextUtil.getApplicationContext();
ERSOrchestrationSvcReqGateway ersOrchestrationSvcReqGateway =
(ERSOrchestrationSvcReqGateway) appCtx.getBean("ersServiceReqRcvGateway");
Message<String> inputMsg = MessageBuilder.withPayload(jsonRequest)
.setHeader(ERSServiceConstants.KEY_MSG_CORRELATION_ID, correlationId)
.setHeader(ERSServiceConstants.KEY_MSG_REPORT_INSTANCE_ID, reportInstanceId)
.build();
Message<String> returnMsg = ersOrchestrationSvcReqGateway.processRequest(inputMsg);
return returnMsg.getPayload();
}
As mentioned in above spring config file, the error-channel is read by a Transformer that creates a valid failed response message for the client and returns the message.
public class ErrorMessageUnwrapTransformer {
@Autowired
private Gson gsonUtil;
@Autowired
private ReportInstanceDAO reportInstanceDAO;
@Autowired
private ERSOrchestrationSvcFailedResMsgBuilder executionSvcFailedMsgBuilder;
private static final ERSOrchestrationSvcDiagnosticLogger _log =
ERSOrchestrationSvcDiagnosticLogger.getInstance(ErrorMessageUnwrapTransformer.class);
@Transformer
public Message<?> handleError(Message<?> message) {
try{
failedMsg = ((MessagingException) message.getPayload()).getFailedMessage();
//some code logic to build a valid failed response message goes here
Message<?> failedResponseMsg = executionSvcFailedMsgBuilder.getERSOrcSvcFailedResMsg(failedMsg );
return failedResponseMsg;
}
All seems to work fine when I get an exception, i.e., the exception is wrapped as MessagingException, put on the error-channel, the Transformer is able to read the channel, get failedMessage out of it, able to create a valid failed response message and return it.
However, the only issue I get is the call does not go back to the caller. In other words, the handle does not go back to the following code that had initiated the processing flow:
Message<String> returnMsg = ersOrchestrationSvcReqGateway.processRequest(inputMsg);
Can someone pls let me know why is the message returned by error-channel-read-Transformer not returning back to the class that invoked the Gateway method ?
回答1:
Your problem here that you return the entire Message<?>
from the transformer
. This one is a component which doesn't care about headers, when the returned object is Message<?>
already. You should worry about them on your own, like copy all headers from the failedMsg
to your own failedResponseMsg
.
Why is that so important?
Since you use request/reply
gateway you are expecting for the return on that method invocation, something on the background ensure that for you. And it is a classical replyChannel
algorithm.
Any AbstractReplyProducingMessageHandler
sends its result to the replyChannel
, if you don't have an outputChannel
configured, like your reqRcvExceptionHandlerChannel
<chain>
here.
With other components we can rely on the copy-header-from-request
function, but not here with the <transformer>
.
From other side ErrorMessage
may be created in some context where we don't have headers, but we exactly may have the failedMessage
in the MessagingException
for which the ErrorMessage
has been caused. So, we have to ensure headers
from that failedMessage
.
Hope I am clear.
来源:https://stackoverflow.com/questions/16894292/spring-integration-response-message-not-sent-to-client-from-error-channel