2015-12-23 33 views
2

我的用例很簡單。我想處理由系統無法訪問導致的異常,根據配置的重試策略執行重試,當滿足重試閾值時發送電子郵件,並將自定義響應返回給調用者。彈簧集成:郵件錯誤和HTTP網關響應

我面臨的挑戰是我無法發送電子郵件並將回覆返回給調用者。由於我使用的是int-mail:outbound-channel-adapter起初,我希望這個行爲,因爲這是一個單向的成分:

<int:chain input-channel="defaultErrorChannel"> 
     <int:service-activator id="mailMessageActivator" expression="@mailHandler.process(payload)" /> 
     <int-mail:outbound-channel-adapter mail-sender="mailSender" /> 
    </int:chain> 

但是,如果我在int-mail:outbound-channel-adapter前面介紹int-amqp:outbound-gateway(見下面的Error Handling配置),我將期望能夠調用int:service-activator來構造並向調用者返回響應。

我在想這個錯誤的方式嗎?我看到其他人有一個similar question,但仍未得到答覆。我提到的兩種配置都會發送電子郵件,但是在超時時間內沒有收到響應,總是阻止來電者。

這裏是我的配置的相關部分:

網關

<int:gateway id="customerGateway" service-interface="com.uscs.crm.integration.CustomerGateway" 
     default-request-channel="syncCustomers" default-reply-channel="replySyncCustomers" default-reply-timeout="30000">   
</int:gateway>  

<int:object-to-json-transformer input-channel="syncCustomers" output-channel="outboundRequestChannel" />  

<int-http:outbound-gateway request-channel="outboundRequestChannel" reply-channel="replySyncCustomers" 
       url="http://voorhees148.uscold.com:9595/web/customerSync/createCustomer" 
       http-method="POST" 
       rest-template="restTemplate" 
       expected-response-type="com.uscs.crm.model.CustSyncResponseVO" 
       mapped-request-headers="Authorization, HTTP_REQUEST_HEADERS"> 
    <int-http:request-handler-advice-chain> 
     <ref bean="retryWithBackoffAdviceSession" /> 
    </int-http:request-handler-advice-chain> 
</int-http:outbound-gateway> 

錯誤處理

<int:channel id="defaultErrorChannel"/> 
    <int:channel id="errorResponses"/> 

    <!-- 
     ExponentialBackOffPolicy.multipler is applied to wait time over each retry attempt 
     with a ExponentialBackOffPolicy.maximum configured.   
    --> 
    <bean id="retryWithBackoffAdviceSession" 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.ExponentialBackOffPolicy"> 
         <property name="initialInterval" value="2000" />  
         <property name="multiplier" value="2" />    
         <property name="maxInterval" value="30000"/>   
        </bean> 
       </property> 
       <property name="retryPolicy"> 
        <bean class="org.springframework.retry.policy.SimpleRetryPolicy"> 
         <property name="maxAttempts" value="3"/> 
        </bean> 
       </property> 
      </bean> 
     </property> 
     <property name="recoveryCallback"> 
      <bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer"> 
       <constructor-arg ref="defaultErrorChannel"/> 
      </bean> 
     </property> 
    </bean> 

    <bean id="custSyncResponseHandler" class="com.uscs.crm.integration.handler.CustSyncResponseHandler"></bean> 
    <int:chain input-channel="defaultErrorChannel" output-channel="replySyncCustomers"> 
     <int:service-activator id="mailMessageActivator" expression="@mailHandler.process(payload)" /> 
     <int:header-enricher> 
      <int:header name="ERROR_ID" expression="T(java.lang.System).currentTimeMillis()"/> 
     </int:header-enricher>   
     <int-amqp:outbound-gateway 
      exchange-name="error-responses-exchange" 
      routing-key-expression="'error.response.'+headers.ERROR_ID" 
      amqp-template="amqpTemplate" /> 
     <!-- Will this service-activator return a response to the caller (int:gateway) using channel `replySyncCustomers`? --> 
     <int:service-activator id="custSyncResponseActivator" expression="@custSyncResponseHandler.process(payload)" />    
    </int:chain>   

    <int-amqp:inbound-gateway queue-names="error-responses" request-channel="errorResponses" 
      connection-factory="rabbitConnectionFactory" acknowledge-mode="AUTO" /> 

    <int-mail:outbound-channel-adapter channel="errorResponses" mail-sender="mailSender" /> 

    <!-- (Outbound Channel Adapter/Gateway) rabbit exchanges, queues, and bindings used by this app --> 
    <rabbit:topic-exchange name="error-responses-exchange" auto-delete="false" durable="true"> 
     <rabbit:bindings> 
      <rabbit:binding queue="error-responses" pattern="error.response.*"/> 
     </rabbit:bindings> 
    </rabbit:topic-exchange> 
    <rabbit:queue name="error-responses" auto-delete="false" durable="true"/>   

解決方案我能夠在@Artem的幫助下完成這項工作。以下是我所做的更改。

服務激活實現(處理ErrorMessage

的關鍵是它返回重建Message與所有的從ErrorMessage頭信息中的線。

@Override 
public Message<CustSyncResponseVO> process(Message<MessagingException> errorMessage) { 

    MessagingException errorException = errorMessage.getPayload(); 

    CustSyncResponseVO custSyncResponse = new CustSyncResponseVO(); 
    custSyncResponse.setResponseMessage(ExceptionUtils 
      .convertToString(errorMessage.getPayload())); 

    return MessageBuilder.withPayload(custSyncResponse) 
     .copyHeaders(errorMessage.getHeaders()) 
     .copyHeadersIfAbsent(errorException.getFailedMessage().getHeaders()).build(); 

} 

服務激活配置

用於規劃環境地政司引用#root上下文檢索ErrorMessage,而不是默認這將是MessagingException(​​),並將其傳遞給我的process對POJO方法。

<bean id="custSyncResponseHandler" class="com.uscs.crm.integration.handler.CustSyncResponseHandler" />   
    <int:chain id="errorGatewayResponseChain" input-channel="defaultErrorChannel" output-channel="replySyncCustomers"> 
     <int:service-activator id="custSyncResponseActivator" expression="@custSyncResponseHandler.process(#root)" /> 
    </int:chain> 

回答

1

我沒有看到有理由介紹AMQP中間件的複雜性,只是爲了最終發送郵件。

你只需要什麼就是<publish-subscribe-channel id="defaultErrorChannel">而終端作爲它的訂閱者。

第一種是單向的電子郵件發送<chain>,第二個是custSyncResponseActivator回覆東西你<int-http:outbound-gateway>

您可以在Spring Integration Reference Manual中找到關於此事的更多信息。

+0

啊,當然。這是完全合理的。我會嘗試一下,讓你知道它是如何工作的。 – Rai

+0

我爲'service-activator'創建了一個'chain',並且需要添加'replyChannel'頭部屬性:''。當我這樣做時,我陷入了無限循環,但是我看到響應被傳遞到'replyCustSyncCustomers'頻道。 '出站網關'似乎不會消耗回覆。最終,我在客戶端收到一個'StackOverflowError'。 – Rai

+0

那麼,你應該根據'ErrorMessage.payload.getFailedMessage()'構建自定義回覆消息。特別是利用它的'headers',你可以在'customerGateway'的'TemporaryReplyChannel'面板找到'replyChannel'。 'gateway'上的'reply-channel'無論如何都使用'replyChannel'來回復網關。 –