javascript
Spring集成和Web服务
本文是我們名為“ Spring Integration for EAI ”的學院課程的一部分。
在本課程中,向您介紹了企業應用程序集成模式以及Spring Integration如何解決它們。 接下來,您將深入研究Spring Integration的基礎知識,例如通道,轉換器和適配器。 在這里查看 !
目錄
1.簡介 2.解釋Web服務通道適配器1.簡介
在本教程中,您將看到使用Spring Integration增強的應用程序的第一個示例。 為了實現這一目標,本示例將重點介紹與外部Web服務的集成。
首先,我將解釋什么是必需的適配器,它將使我們能夠從Spring Integration調用Web服務。 接下來,我們將對Spring Web Services項目進行簡要說明,該項目將是將從我們的應用程序中調用的外部Web服務。 在完成本教程的主要部分之后,我們將實現一個將調用Web服務的應用程序。
結束本教程,我們將使用Spring Integration提供的一些功能來完成我們的應用程序,例如添加超時,使用攔截器以及學習如何重試失敗的調用。
本教程由以下部分組成:
- 介紹
- 解釋Web服務通道適配器
- 創建一個Spring Web Services項目
- 實施Spring Integration流程
- 添加客戶端超時
- 使用攔截器
- Web服務重試操作
2.解釋Web服務通道適配器
與外部Web服務的通信是通過帶有網關的Spring Integration完成的。 如上一教程中所述,您可以找到兩種類型的網關:入站和出站。 在本教程中,我們將使用一種特殊的網關:出站Web服務網關 。 在本節中,我們將重點介紹這種類型。
為了使用Web服務網關,您將需要指定一個新的名稱空間:
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:int="http://www.springframework.org/schema/integration"xmlns:int-ws="http://www.springframework.org/schema/integration/ws"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsdhttp://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd">設置了新的名稱空間后,我們現在可以使用Web服務網關:
<int-ws:outbound-gateway id="aGateway"request-channel="requestChannel" reply-channel="responseChannel"uri="http://localhost:8080/spring-ws-tickets/tickets" marshaller="marshaller"unmarshaller="marshaller"/>那么,此網關的行為是什么? 該流程的執行如下:
如您所見,您只需要定義流(請求和答復通道)以及調用位置。 發送消息所需的基礎結構詳細信息由Spring Integration處理。
其他屬性
還有其他一些屬性可用于定制網關的調用。 以下是主要屬性的簡要說明:
- Destination provider:可以使用它代替提供“ uri”屬性。 這樣,您可以實現自己的類,該類將動態解析調用了哪個端點。 您應該為bean提供以下接口:
在網關定義中,我們可以使用此提供程序來代替直接提供URI:
<int-ws:outbound-gateway id="aGateway"request-channel="requestChannel" reply-channel="responseChannel" destination-provider="myDestinationProvider"marshaller="marshaller" unmarshaller="marshaller"/>- Message sender:允許我們定義一個WebServiceMessageSender 。 在本教程的后面,我們將使用它來定義客戶端超時。
- Interceptor/Interceptors:您可以定義客戶端攔截器。 這也將在本教程的后面部分中進行說明。
入站Web服務網關
本部分只是為了快速了解入站服務網關,以了解其一般工作原理,因為在本教程中我們將不使用它。
該網關將接收來自外部服務的請求,將該請求包裝為消息,然后將其發送到我們的消息傳遞系統中。 處理完請求后,將向網關發送一條消息,以傳遞Web服務正在等待的響應。
語法類似于出站Web服務網關:
<int-ws:inbound-gateway id="anotherGateway" request-channel="requestChannel" marshaller="marshaller" unmarshaller="marshaller"/>您可能還記得以前的教程,響應將通過臨時消息通道到達網關。 如果沒有必要,請不要顯式定義通道。
3.創建一個Spring Web Services項目
本節說明將公開我們的應用程序將使用的Web服務的項目。 它包含一個使用Spring Web Services項目實現的Web應用程序。
該應用程序非常簡單。 它包含一個服務界面,該界面允許用戶從電影院服務訂購門票。 請求訂單時,服務將對其進行處理并返回TicketConfirmation 。
下圖顯示了其結構:
圖1
我們將從下至上進行解釋。
票務服務界面
這是服務接口和實現:
public interface TicketService {public TicketConfirmation order(String filmId, Date sessionDate, int quantity); }該實現根據提供的數據構建TicketConfirmation實例。
@Service public class TicketServiceimpl implements TicketService {@Overridepublic TicketConfirmation order(String filmId, Date sessionDate, int quantity) {float amount = 5.95f * quantity;TicketConfirmation confirmation = new TicketConfirmation(filmId, sessionDate, quantity, amount);return confirmation;} }TicketConfirmation對象是一個不變的類,將用于讀取確認數據:
public final class TicketConfirmation {private String confirmationId;private String filmId;private int quantity;private Date sessionDate;private float amount;public TicketConfirmation(String filmId, Date sessionDate, int quantity, float amount) {this.confirmationId = UUID.randomUUID().toString();this.filmId = filmId;this.sessionDate = new Date(sessionDate.getTime());this.quantity = quantity;this.amount = amount;}public String getConfirmationId() {return confirmationId;}public String getFilmId() {return filmId;}public int getQuantity() {return quantity;}public Date getSessionDate() {return new Date(sessionDate.getTime());}public float getAmount() {return amount;} }票證端點
端點負責接收請求并將訂單處理委托給Ticket服務:
@Endpoint public class TicketEndpoint {@Autowiredprivate TicketService ticketService;@PayloadRoot(localPart="ticketRequest", namespace="http://www.xpadro.spring.samples.com/tickets")public @ResponsePayload TicketResponse order(@RequestPayload TicketRequest ticketRequest) throws InterruptedException {Calendar sessionDate = Calendar.getInstance();sessionDate.set(2013, 9, 26);TicketConfirmation confirmation = ticketService.order(ticketRequest.getFilmId(), DateUtils.toDate(ticketRequest.getSessionDate()), ticketRequest.getQuantity().intValue());return buildResponse(confirmation);}private TicketResponse buildResponse(TicketConfirmation confirmation) {TicketResponse response = new TicketResponse();response.setConfirmationId(confirmation.getConfirmationId());response.setFilmId(confirmation.getFilmId());response.setSessionDate(DateUtils.convertDate(confirmation.getSessionDate()));BigInteger quantity = new BigInteger(Integer.toString(confirmation.getQuantity()));response.setQuantity(quantity);BigDecimal amount = new BigDecimal(Float.toString(confirmation.getAmount()));response.setAmount(amount);return response;} }該服務將接收使用命名空間"http://www.xpadro.spring.samples.com/tickets"和ticketRequest請求元素ticketRequest請求。
服務配置
在Spring配置中,我們定義了Web服務組件:
<!-- Detects @Endpoint since it is a specialization of @Component --> <context:component-scan base-package="xpadro.spring.ws"/><!-- detects @PayloadRoot --> <ws:annotation-driven/><ws:dynamic-wsdl id="ticketDefinition" portTypeName="Tickets" locationUri="http://localhost:8080/spring-ws-tickets"><ws:xsd location="/WEB-INF/schemas/xsd/ticket-service.xsd"/> </ws:dynamic-wsdl>web.xml文件公開了MessageDispatcherServlet:
<context-param><param-name>contextConfigLocation</param-name><param-value>classpath:xpadro/spring/ws/config/root-config.xml</param-value> </context-param><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener><servlet><servlet-name>Ticket Servlet</servlet-name><servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:xpadro/spring/ws/config/servlet-config.xml</param-value></init-param><load-on-startup>1</load-on-startup> </servlet><servlet-mapping><servlet-name>Ticket Servlet</servlet-name><url-pattern>/tickets/*</url-pattern> </servlet-mapping>現在,我們只需要將其部署到服務器中,即可開始處理票單請求。
4.實施Spring集成流程
我們的Spring Integration應用程序從一個簡單的流程開始。
圖2
該請求消息將通過系統入口網關。 然后,該消息將傳遞到Web服務出站網關,該網關將其發送到端點并等待響應。 收到響應后,它將通過響應通道發送響應,然后返回系統入口網關,然后系統入口網關會將其傳遞給客戶端。
客戶端應用程序將TicketRequest發送到TicketService接口。 該接口被網關攔截。 通過這種方式, TicketRequest對象被包裝到Spring Integration消息中并發送到消息傳遞系統。
public interface TicketService {/*** Entry to the messaging system. * All invocations to this method will be* intercepted and sent to the SI "system entry" gateway* * @param request*/@Gatewaypublic TicketResponse invoke(TicketRequest request); }查看網關配置,我們可以看到已將其鏈接到TicketService接口:
<int:gateway id="systemEntry" default-request-channel="requestChannel" default-reply-channel="responseChannel"service-interface="xpadro.spring.integration.ws.gateway.TicketService" />我們還定義了請求和回復渠道。
該請求消息將被發送到requestChannel通道,在該通道上訂閱了Web服務出站網關:
<int-ws:outbound-gateway id="marshallingGateway"request-channel="requestChannel" reply-channel="responseChannel"uri="http://localhost:8080/spring-ws-tickets/tickets" marshaller="marshaller"unmarshaller="marshaller"/>responseChannel被配置為其回復通道,系統進入網關已在該通道中訂閱。 這樣,客戶端將收到響應。
使用直接通道配置完整流。 這意味著流程是同步的; 客戶端將阻止等待Web服務響應:
<context:component-scan base-package="xpadro.spring.integration" /><!-- Entry to the messaging system --> <int:gateway id="systemEntry" default-request-channel="requestChannel" default-reply-channel="responseChannel"service-interface="xpadro.spring.integration.ws.gateway.TicketService" /><int:channel id="requestChannel"/><int-ws:outbound-gateway id="marshallingGateway"request-channel="requestChannel" reply-channel="responseChannel"uri="http://localhost:8080/spring-ws-tickets/tickets" marshaller="marshaller"unmarshaller="marshaller"/><oxm:jaxb2-marshaller id="marshaller" contextPath="xpadro.spring.integration.ws.types" /><int:channel id="responseChannel" />系統已設置; 我們不必實現任何Java類。 全部通過配置進行配置。
在完成示例之后,讓我們看一下執行此流程的測試:
@ContextConfiguration({"classpath:xpadro/spring/integration/ws/test/config/int-ws-config.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class TestInvocation {@Autowiredprivate TicketService service;@Testpublic void testInvocation() throws InterruptedException, ExecutionException {TicketRequest request = new TicketRequest();request.setFilmId("aFilm");request.setQuantity(new BigInteger("3"));request.setSessionDate(DateUtils.convertDate(new Date()));TicketResponse response = service.invoke(request);assertNotNull(response);assertEquals("aFilm", response.getFilmId());assertEquals(new BigInteger("3"), response.getQuantity());} }在下一節中,我們將向此示例應用程序添加一些功能。
5.添加客戶端超時
檢查網關的名稱空間,我們可以看到沒有用于設置調用超時的配置。 無論如何,我們都可以使用消息發送者。
消息發送者是WebServiceMessageSender的實現。 Spring Web Services項目提供的一種有趣的實現是HttpComponentsMessageSender類。 此類將允許我們通過內部使用Apache HttpClient將身份驗證或連接池添加到調用中。 而且,我們還將能夠定義讀取和連接超時。
在此示例之后,我們將其添加為超時。
首先,我們需要使用上述類定義一個bean。 這將是我們的消息發件人:
<bean id="messageSender" class="org.springframework.ws.transport.http.HttpComponentsMessageSender"><property name="connectionTimeout" value="5000"/><property name="readTimeout" value="10000"/> </bean>接下來,我們將在我們的Web服務網關中配置消息發送者:
<int-ws:outbound-gateway id="marshallingGateway"request-channel="requestChannel" reply-channel="responseChannel"uri="http://localhost:8080/spring-ws-tickets/tickets" marshaller="marshaller"unmarshaller="marshaller" message-sender="messageSender"/>而已。 現在,如果達到超時,將拋出WebServiceIOException 。
6.使用攔截器
Web服務網關的名稱空間中包含的另一個功能是可以配置客戶端攔截器。 這些客戶端攔截器是Spring Web Services項目的功能,并且引用客戶端上的端點攔截器。 ClientInterceptor實現具有以下方法:
public interface ClientInterceptor {boolean handleRequest(MessageContext messageContext) throws WebServiceClientException;boolean handleResponse(MessageContext messageContext) throws WebServiceClientException;boolean handleFault(MessageContext messageContext) throws WebServiceClientException; }- handleRequest :在調用端點之前調用此方法。
- handleResponse :在端點成功返回之后,將調用此方法。
- handleFault :如果端點拋出錯誤,則調用此方法。
注意,這些方法可以操縱MessageContext ,該MessageContext包含請求和響應。
讓我們看一個例子。 我們將實現自定義客戶端攔截器以在調用端點之前攔截該調用,并且將更改請求值。
攔截器實現ClientInterceptor接口:
public class MyInterceptor implements ClientInterceptor {private Logger logger = LoggerFactory.getLogger(this.getClass());@Overridepublic boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {WebServiceMessage message = messageContext.getRequest();DOMSource source = (DOMSource) message.getPayloadSource();Node quantityNode = source.getNode().getAttributes().getNamedItem("quantity");String oldValue = quantityNode.getNodeValue();quantityNode.setNodeValue("5");logger.info("Before endpoint invocation. Changed quantity old value {} for {}", oldValue, 5);return true;}@Overridepublic boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {logger.info("endpoint invocation succeeds");return true;}@Overridepublic boolean handleFault(MessageContext messageContext) throws WebServiceClientException {logger.info("endpoint returned a fault");return true;} }現在,我們需要將攔截器添加到網關配置中:
<int-ws:outbound-gateway id="marshallingGateway"request-channel="requestChannel" reply-channel="responseChannel"uri="http://localhost:8080/spring-ws-tickets/tickets" marshaller="marshaller"unmarshaller="marshaller" message-sender="messageSender" interceptor="myInterceptor" /><bean id="myInterceptor" class="xpadro.spring.integration.ws.interceptor.MyInterceptor" />Web服務網關名稱空間還允許我們定義interceptors屬性。 這使我們可以配置客戶端攔截器列表。
該測試將驗證請求值已被修改:
@ContextConfiguration({"classpath:xpadro/spring/integration/ws/test/config/int-ws-config.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class TestInvocation {@Autowiredprivate TicketService service;@Testpublic void testInvocation() throws InterruptedException, ExecutionException {TicketRequest request = new TicketRequest();request.setFilmId("aFilm");request.setQuantity(new BigInteger("3"));request.setSessionDate(DateUtils.convertDate(new Date()));TicketResponse response = service.invoke(request);assertNotNull(response);assertEquals("aFilm", response.getFilmId());assertEquals(new BigInteger("5"), response.getQuantity());} }在實現自定義攔截器之前,請考慮到Spring Web Services項目提供了幾種實現:
- PayloadValidatingInterceptor :使用模式驗證Web服務消息的有效負載。 如果未通過驗證,則處理將被取消。
- Wss4jSecurityInterceptor :基于Apache的WSS4J的Web服務安全端點攔截器。
- XwsSecurityInterceptor :基于Sun的XML和Web服務安全包的Web服務安全端點攔截器。
7. Web服務重試操作
有時,我們可能想調用一項服務,但該服務暫時關閉,或者該服務僅在某些日子才在線。 如果發生這種情況,我們可能要稍后重試調用。 Spring Integration提供了開始重試服務調用直到滿足條件的可能性。 這種情況可能是服務最終響應,或者我們達到了最大嘗試次數。 對于此功能,Spring Integration提供了重試建議。 該建議由Spring Retry項目提供支持。
重試建議包含在Web服務出站網關中。 這樣,網關將Web服務調用委托給重試建議。 如果服務調用失敗,則建議將根據其配置繼續嘗試重試該操作。
定義重試建議
我們必須使用RequestHandlerRetryAdvice類定義一個新bean:
<bean id="retryAdvice" 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="5000" /></bean></property><property name="retryPolicy"><bean class="org.springframework.retry.policy.SimpleRetryPolicy"><property name="maxAttempts" value="5" /></bean></property></bean></property> </bean>我們定義了一個建議,如果調用失敗,它將每5秒重新嘗試一次,直到服務響應或嘗試5次為止。 稍后我們將查看建議中定義的這些策略。
將建議添加到網關
定義建議后,我們需要將其包含在網關中。 Spring Integration Web Services名稱空間已經為此提供了一個元素:
<int-ws:outbound-gateway id="marshallingGateway"request-channel="requestChannel" reply-channel="responseChannel"uri="http://localhost:8080/spring-ws-tickets/tickets" marshaller="marshaller"unmarshaller="marshaller" message-sender="messageSender" interceptor="myInterceptor" ><int-ws:request-handler-advice-chain><ref bean="retryAdvice" /></int-ws:request-handler-advice-chain> </int-ws:outbound-gateway>我們已將建議集成到網關中。 現在,讓我們修改示例以查看其工作原理。
修改Web服務端點
我們將修改端點,以便在嘗試指定次數的重試之前一直失敗。 在這種情況下,需要兩次直到返回響應。
@PayloadRoot(localPart="ticketRequest", namespace="http://www.xpadro.spring.samples.com/tickets") public @ResponsePayload TicketResponse order(@RequestPayload TicketRequest ticketRequest) throws InterruptedException {Calendar sessionDate = Calendar.getInstance();sessionDate.set(2013, 9, 26);TicketConfirmation confirmation = ticketService.order(ticketRequest.getFilmId(), DateUtils.toDate(ticketRequest.getSessionDate()), ticketRequest.getQuantity().intValue());TicketResponse response = buildResponse(confirmation);retries++;if (retries < 3) {throw new RuntimeException("not enough retries");}else {retries = 0;}return response; }現在,我們將啟動測試并使用我們先前定義的攔截器來查看它如何記錄嘗試:
2014-03-26 08:24:50,535|AbstractEndpoint|started org.springframework.integration.endpoint.EventDrivenConsumer@392044a1 2014-03-26 08:24:50,626|MyInterceptor|Before endpoint invocation. Changed quantity old value 3 for 5 2014-03-26 08:24:51,224|MyInterceptor|endpoint returned a fault 2014-03-26 08:24:56,236|MyInterceptor|Before endpoint invocation. Changed quantity old value 3 for 5 2014-03-26 08:24:56,282|MyInterceptor|endpoint returned a fault 2014-03-26 08:25:01,285|MyInterceptor|Before endpoint invocation. Changed quantity old value 3 for 5 2014-03-26 08:25:01,377|MyInterceptor|endpoint invocation succeeds網關一直嘗試調用,直到服務響應為止,因為重試建議具有較高的重試次數(五個)。
重試建議政策
Spring Integration重試建議是在Spring Retry項目策略上備份的。 這些政策說明如下:
退避政策
它確定了重試之間或初次重試之前的時間。 BackOffPolicy接口定義了兩種方法:
BackOffContext start(RetryContext context);
void backOff(BackOffContext backOffContext)拋出BackOffInterruptedException;
start方法允許定義初始行為。 例如,初始時間延遲。
backoff方法允許定義重試之間的暫停。Spring Retry項目提供了回退策略的幾種實現:
- 無狀態退避策略:調用之間不保持任何狀態。
- FixedBackOffPolicy:重試之間暫停指定的時間。 沒有設置初始延遲。
- NoBackOffPolicy:重試在它們之間完全沒有暫停地執行。
- 有狀態的后退策略:在調用之間保持狀態。
- ExponentialBackOffPolicy:從指定的時間量開始,它將在每次調用時相乘。 默認情況下,它使時間加倍。 您可以更改乘數。
- ExponentialRandomBackOffPolicy:擴展ExponentialBackOffPolicy 。 乘數以隨機方式設置。
- SimpleRetryPolicy:重試調用,直到達到最大重試次數。
- TimeoutRetryPolicy:它將一直重試,直到達到超時為止。 在打開方法期間開始超時。
- NeverRetryPolicy:它只會嘗試一次調用。
- AlwaysRetryPolicy: canRetry方法始終返回true。 它將繼續重試,直到服務響應為止。
- ExceptionClassifierRetryPolicy:根據拋出的ExceptionClassifierRetryPolicy:它定義了不同的最大嘗試次數。
- CompositeRetryPolicy:它包含將按順序執行的重試策略的列表。
重試政策
它允許定義重試建議在放棄之前將執行Web服務調用多少次。 RetryPolicy接口定義了幾種方法:
boolean canRetry(RetryContext context);
RetryContext open(RetryContext parent);
void close(RetryContext context);
void registerThrowable(RetryContext context,Throwable throwable);
如果可以重試該操作,則canRetry方法將返回。 例如,如果我們尚未達到最大重試次數,則可能發生這種情況。
open方法用于獲取所有必要的資源,跟蹤嘗試次數或在上一次重試期間是否引發異常。
每次失敗的調用后都會調用registerThrowable方法。
Spring Retry項目提供了重試策略的幾種實現:
使用輪詢器重試操作
可用的重試策略是使用時間延遲實現的,這在大多數情況下都很好,但是在本節中,我們將實現一個自定義解決方案,該解決方案將使我們能夠使用通過Cron Expression配置的輪詢器。
由于調用可能會失敗,因此網關不會返回結果。 我們將使流程異步,以便允許客戶端發送服務請求并繼續。 這樣,流將繼續從另一個線程重試,直到服務激活程序處理結果或達到重試限制為止。
網關如下:
public interface AsyncTicketService {@Gatewaypublic void invoke(TicketRequest request); }網關未定義回復通道,因為不會發送響應。 由于這是一個異步請求,因此請求通道包含一個隊列。 這將允許其使用者主動輪詢來自另一個線程的消息:
<int:gateway id="systemEntry" default-request-channel="requestChannel"service-interface="xpadro.spring.integration.ws.gateway.AsyncTicketService" /><int:channel id="requestChannel"><int:queue /> </int:channel>我們已經在Web服務網關中包含了一個輪詢器,因為現在它將輪詢消息:
<int-ws:outbound-gateway id="marshallingGateway"request-channel="requestChannel" reply-channel="responseChannel"uri="http://localhost:8080/spring-ws-tickets/tickets" marshaller="marshaller"unmarshaller="marshaller" interceptor="myInterceptor" ><int:poller fixed-rate="500" /> </int-ws:outbound-gateway>先前的調用可能導致三種不同的結果:正確的調用,需要重試的失敗調用以及需要記錄的最終失敗的調用。
服務調用已正確調用
我們有一個服務激活器訂閱了響應通道。 這是一個簡單的示例,因此只記錄結果:
<!-- Service is running - Response received --> <int:channel id="responseChannel" /> <int:service-activator ref="clientServiceActivator" method="handleServiceResult" input-channel="responseChannel" />服務調用失敗。 重試該操作
如果出現問題,并且由于它是異步請求,則該異常將被包裝到MessageHandlingException ,并發送到錯誤通道,該通道由Spring Integration默認配置。
至此,我們已經有一個路由器訂閱了錯誤通道。 該路由器處理嘗試的重試次數,并基于此嘗試將失敗的消息重定向到適當的通道。 如果要重試該操作,它將把消息發送到重試通道:
@Component("serviceRouter") public class ServiceRouter {private Logger logger = LoggerFactory.getLogger(this.getClass());private int maxRetries = 3;private int currentRetries;public String handleServiceError(Message<?> msg) {logger.info("Handling service failure");if (maxRetries > 0) {currentRetries++;if (currentRetries > maxRetries) {logger.info("Max retries [{}] reached", maxRetries);return "failedChannel"; }}logger.info("Retry number {} of {}", currentRetries, maxRetries);return "retryChannel";} }路由器的配置如下所示:
<!-- Service invocation failed --> <int:router ref="serviceRouter" method="handleServiceError" input-channel="errorChannel"/> <int:channel id="retryChannel" /> <int:channel id="failedChannel" />接下來,我們有以下這些端點:
<!-- Retry --> <int:service-activator ref="clientServiceActivator" method="retryFailedInvocation" input-channel="retryChannel" /><int:inbound-channel-adapter id="retryAdapter" channel="requestChannel" ref="clientServiceActivator" method="retryInvocation" auto-startup="false"><int:poller cron="0/5 * * * * *"/> </int:inbound-channel-adapter><!-- Log failed invocation --> <int:service-activator ref="clientServiceActivator" method="handleFailedInvocation" input-channel="failedChannel" />retryAdapter入站通道適配器將繼續輪詢請求通道,但是請注意,屬性auto-startup設置為false。 這意味著該適配器將被禁用,直到有人激活它為止。 我們需要這樣做,否則它將從頭開始輪詢,并且我們只想在發生失敗的調用時將其激活。
服務激活器將根據服務調用的結果啟動或停止適配器。 失敗時,它將啟動適配器以開始重試。 如果達到最大重試次數,則路由器會將消息重定向到失敗的通道,在該通道中,服務激活器將禁用適配器以阻止其輪詢。 如果調用最終成功,它將記錄消息并停止適配器。
@Component("clientServiceActivator") public class ClientServiceActivator {private Logger logger = LoggerFactory.getLogger(this.getClass());@Autowired@Qualifier("retryAdapter")private AbstractEndpoint retryAdapter;private Message<?> message;public void handleServiceResult(Message<?> msg) {logger.info("service successfully invoked. Finishing flow");retryAdapter.stop();}public void retryFailedInvocation(Message<?> msg) {logger.info("Service invocation failed. Activating retry trigger...");MessageHandlingException exc = (MessageHandlingException) msg.getPayload();this.message = exc.getFailedMessage();retryAdapter.start();}public Message<?> retryInvocation() {logger.info("Retrying service invocation...");return message;}public void handleFailedInvocation(MessageHandlingException exception) {logger.info("Maximum number of retries reached. Finishing flow.");retryAdapter.stop();} }測試類已被修改,以免產生以下結果:
@ContextConfiguration({"classpath:xpadro/spring/integration/ws/test/config/int-ws-async-config.xml"}) @RunWith(SpringJUnit4ClassRunner.class) public class TestAsyncInvocation {@Autowiredprivate AsyncTicketService service;@Testpublic void testInvocation() throws InterruptedException, ExecutionException {TicketRequest request = new TicketRequest();request.setFilmId("aFilm");request.setQuantity(new BigInteger("3"));request.setSessionDate(DateUtils.convertDate(new Date()));service.invoke(request);Thread.sleep(80000);} }而已。 顯然,無需知道我們可以使用Spring Retry項目的重試建議就可以實現所有這些流程,但是此示例的目的是獲得更多有關如何使用適配器的激活和停用來構建更復雜的流程的知識,路由器重定向和其他功能可以滿足您的需求。
8.下載源代碼
您可以從此處下載有關spring集成和Web服務的源代碼: Spring_Integration_Sample.zip和Spring_WS_Sample.zip
翻譯自: https://www.javacodegeeks.com/2015/09/spring-integration-and-web-services.html
總結
以上是生活随笔為你收集整理的Spring集成和Web服务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 电脑硬盘完全清零(电脑硬盘清空)
- 下一篇: 课程格子APP怎么修改密码?课程格子AP