如何在关机时等待RestTemplate响应?
我正在使用带RestTemplate
将POST
请求发送到网络服务器。
当我的应用程序关闭时(例如从tomcat取消部署),应该延迟关闭,直到收到所有挂起的响应(在超时内)。
restTemplate在引擎盖下使用HttpComponentsClientHttpRequestFactory
。
问题:如何告诉spring
延迟关机? @PreDestroy
可能是一种可能,但我如何检测restTemplate上的待处理请求?
我认为没有开箱即用的解决方案,如https://github.com/spring-projects/spring-boot/issues/4657中所述
对于下面的Tomcat代码应该可行
@Component @Scope("singleton") public class ApplicationContextClosedListener implements ApplicationListener, TomcatConnectorCustomizer { private static final Logger LOGGER = LoggerFactory.getLogger(ApplicationContextClosedListener.class); private volatile Connector connector; @Value("${timeout}") private Integer timeout; @Override public void customize(Connector connector) { this.connector = connector; } @Override public void onApplicationEvent(ContextClosedEvent event) { if (connector != null) { shutdownGracefully(); } } private void shutdownGracefully() { connector.pause(); Executor executor = connector.getProtocolHandler().getExecutor(); if (executor instanceof ThreadPoolExecutor) { ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executor; try { threadPoolExecutor.shutdown(); if (!threadPoolExecutor.awaitTermination(timeout, TimeUnit.SECONDS)) { LOGGER.warn("Shutdown: Tomcat thread pool did not shut down gracefully within specified period. Proceeding with forceful shutdown"); } threadPoolExecutor.shutdownNow(); LOGGER.info("Shutdown: the executor shutdown completed"); } catch (InterruptedException ex) { LOGGER.error("Shutdown: Interrupt signal received"); threadPoolExecutor.shutdownNow(); Thread.currentThread().interrupt(); } } } }
您可以使用ExecutorService
执行所有请求,然后添加@PreDestroy
挂钩以等待在给定超时内完成所有任务。 您的服务可以是这样的
@Slf4j @Component public class SenderService { private static final int TWO_SECONDS = 2; private RestTemplate restTemplate; private ExecutorService executorService; public SenderService() { this.restTemplate = new RestTemplate(); this.executorService = Executors.newFixedThreadPool(1); } public void sendRequest() throws Exception { executorService.submit(() -> { ZonedDateTime now = ZonedDateTime.now(); log.info("Sending request at {} ...", now); restTemplate.getForObject("https://httpbin.org/delay/{delay}", Void.class, TWO_SECONDS, now); log.info("Response received for request at {}", now); return null; }).get(); } @PreDestroy public void destroy() throws InterruptedException { log.info("Shutting down sender service..."); executorService.shutdown(); executorService.awaitTermination(3, TimeUnit.SECONDS); log.info("Sender service terminated."); } }
测试这个的简单方法是运行下面的应用程序并在某个时候终止它。
@SpringBootApplication public class Application { public static void main(final String[] args) throws Exception { ConfigurableApplicationContext run = SpringApplication.run(Application.class, args); SenderService senderService = run.getBean(SenderService.class); while (true) { senderService.sendRequest(); } } }
如果您正常关闭应用程序,您将看到如果将请求发送到delay endpoint
,则executorService
将等待最多3秒钟以完成任务,然后终止该组件。 executorService.shutdown()
启动关闭,在该关闭中执行先前提交的任务,但不接受任何新任务。
此代码使用带有嵌入式tomcat的spring-boot,但是相同的方法可以应用于任何spring应用程序上下文。
- 使用HTML5 localStorage在GWT app / widget中缓存
- 使用outputstream序列化对象
- 在编译过程方面,Java Runtime Environment如何与.NET框架进行比较?
- 为什么我的表在JScrollPane中不可见?
- Servlet重定向到同一页面,并显示错误消息
- 使用我的第一个Maven,Spring项目获取org.springframework.beans.factory.BeanCreationException
- 在java中创建一组数组
- 我可以使用MyBatis生成动态SQL而不执行它吗?
- Spring Data JPA JpaRepository.save(实体)不返回数据库默认值