1.引言
有时在调用Web服务时,我们可能有兴趣在发生错误的情况下重试该操作。 使用Spring Integration时,我们可以使用RequestHandlerRetryAdvice类实现此功能。 此类将使我们在放弃并引发异常之前重试指定次数的操作。 这篇文章将向您展示如何完成此任务。
测试应用程序将调用Web服务,如果响应失败,它将等待指定的时间,然后重试,直到收到响应或达到重试限制为止。 如果达到限制,失败的请求将被存储到数据库中。 主要,这篇文章显示以下示例:
该应用程序的源代码可以在github上找到。
您还可以在github上获取由应用程序调用的Web服务项目的源代码。
2.Web服务调用
用例 :客户端调用Web服务并接收响应。
该请求通过“系统入口”网关进入消息传递系统。 然后,它到达出站网关,调用Web服务并等待响应。 收到响应后,将其发送到响应通道。
上图是此配置的结果:
<context:component-scan base-package="xpadro.spring.integration" />
<!-- Initial service request -->
<int:gateway id="systemEntry" default-request-channel="requestChannel"
service-interface="xpadro.spring.integration.gateway.ClientService" />
<int:channel id="requestChannel">
<int:queue />
</int:channel>
<int-ws:outbound-gateway id="marshallingGateway"
request-channel="requestChannel" reply-channel="responseChannel"
uri="http://localhost:8080/spring-ws/orders" marshaller="marshaller"
unmarshaller="marshaller">
<int:poller fixed-rate="500" />
</int-ws:outbound-gateway>
<oxm:jaxb2-marshaller id="marshaller" contextPath="xpadro.spring.integration.types" />
<!-- Service is running - Response received -->
<int:channel id="responseChannel" />
<int:service-activator ref="clientServiceActivator" method="handleServiceResult" input-channel="responseChannel" />
映射到响应通道的是一个服务激活器,它仅记录结果。
TestInvocation.java:将请求发送到入口网关
@ContextConfiguration({"classpath:xpadro/spring/integration/config/int-config.xml",
"classpath:xpadro/spring/integration/config/mongodb-config.xml"})
@RunWith(SpringJUnit4ClassRunner.class)
public class TestInvocation {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private ClientService service;
@Test
public void testInvocation() throws InterruptedException, ExecutionException {
logger.info("Initiating service request...");
ClientDataRequest request = new ClientDataRequest();
request.setClientId("123");
request.setProductId("XA-55");
request.setQuantity(new BigInteger("5"));
service.invoke(request);
logger.info("Doing other stuff...");
Thread.sleep(60000);
}
}
使用此配置,如果服务调用失败,则将引发MessagingException并将其发送到错误通道。 在下一节中,我们将添加重试配置。
3.添加重试建议
用例 :初始请求失败,因为该服务未激活。 我们将重试该操作,直到从服务收到响应为止。
在这种情况下,我们需要将重试建议添加到Web服务出站网关:
<int-ws:outbound-gateway id="marshallingGateway" interceptor="clientInterceptor"
request-channel="requestChannel" reply-channel="responseChannel"
uri="http://localhost:8080/spring-ws/orders" marshaller="marshaller"
unmarshaller="marshaller">
<int:poller fixed-rate="500" />
<int-ws:request-handler-advice-chain>
<ref bean="retryAdvice" />
</int-ws:request-handler-advice-chain>
</int-ws:outbound-gateway>
现在,Web服务出站网关会将调用委派给重试建议,重试建议将按指定的次数尝试操作多次,直到从服务获得响应为止。 让我们定义重试建议:
<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="4000" />
</bean>
</property>
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="4" />
</bean>
</property>
</bean>
</property>
</bean>
为了实现其目标,建议使用RetryTemplate,该模板由Spring Retry项目提供。 我们可以通过定义退避和重试策略来自定义其行为。
退避政策 :在每次重试之间建立一段时间。 更有趣的类型是:
- FixedBackOffPolicy :在我们的示例中使用。 每次重试之间将等待相同的指定时间。
- ExponentialBackOffPolicy :从确定的时间量开始,它将使每次重试的时间加倍。 您可以通过建立乘数来更改默认行为。
重试策略 :确定将重试失败操作的次数。 一些类型:
- SimpleRetryPolicy :在我们的示例中使用。 指定重试次数限制。
- ExceptionClassifierRetryPolicy :允许我们根据引发的异常来建立不同的maxAttempts。
- TimeoutRetryPolicy :将继续重试,直到达到超时为止。
4,不走运,记录失败的请求
用例 :服务将无法恢复,无法将请求存储到数据库中。
配置的最后部分如下:
<!-- Log failed invocation -->
<int:service-activator ref="clientServiceActivator" method="handleFailedInvocation" input-channel="errorChannel" output-channel="logChannel" />
<int:channel id="logChannel" />
<bean id="mongoDbFactory" class="org.springframework.data.mongodb.core.SimpleMongoDbFactory">
<constructor-arg>
<bean class="com.mongodb.Mongo"/>
</constructor-arg>
<constructor-arg value="test"/>
</bean>
<int-mongodb:outbound-channel-adapter id="mongodbAdapter" channel="logChannel"
collection-name="failedRequests" mongodb-factory="mongoDbFactory" />
订阅错误通道的服务激活器将检索失败的消息并将其发送到出站适配器,出站适配器会将其插入到mongoDB数据库中。 服务激活器:
public Message<?> handleFailedInvocation(MessagingException exception) {
logger.info("Failed to succesfully invoke service. Logging to DB...");
return exception.getFailedMessage();
}
如果我们未能成功从服务获得响应,则该请求将存储到数据库中:
六,结论
我们已经了解了Spring Integration如何从Spring Retry项目获得支持以实现操作的重试。 我们使用了int-ws:request-handler-advice-chain ,但是'int'命名空间也支持此元素,以将该功能添加到其他类型的端点。