如何使用Spring正确关闭执行器服务?

问题描述 投票:0回答:5

我有一个命令行应用程序,它使用 Spring 管理的 bean,该 bean 由使用以下命令创建的 java

ExecutorService
组成:

ExecutorService service = Executors.newFixedThreadPool(4);

现在,我希望我的服务在我的应用程序关闭时关闭,所以我让我的 bean 实现

DisposableBean
接口并具有一个销毁方法,例如:

public void destroy(){
  service.shutdown();
}

然后我可能会想做一些事情,比如在 Spring 上下文中注册一个关闭钩子。然而我发现(艰难的方式,即在预生产版本中)这不起作用:在调用

ExecutorService.shutdown()
方法之前不会调用关闭挂钩,导致经典的 catch 22 问题(它确实会在中断时被调用,即,如果我在应用程序运行时按 Ctrl-C)。这逃脱了我的单元测试,因为出于某种原因,它似乎在 JUnit 中工作得很好,这仍然让我感到困惑:JUnit 的做法有何不同?

到目前为止我找到的解决方案是在退出主函数之前显式调用

ApplicationContext.close()
。我想知道是否有更好的解决方案,以及由 Spring 管理灵活线程池的最佳实践是什么。另外,如果我的 bean not 由 Spring 直接管理,而是由 Spring 管理的 bean 创建,该怎么办?我应该将呼叫级联到
destroy()
吗?这不是很容易出错吗?

我感谢任何评论、建议、进一步阅读、RTFM、神奇食谱。

谢谢!

java multithreading spring junit executorservice
5个回答
27
投票

你知道吗:

ExecutorService service = Executors.newFixedThreadPool(4);

可以用这个代替:

<bean id="service" class="java.util.concurrent.Executors" 
      factory-method="newFixedThreadPool" destroy-method="shutdown">
    <constructor-arg value="4"/>
</bean>

Spring 上下文会更直接地管理执行器服务的关闭——并且可以更轻松地重用它。


9
投票

根据 Spring 官方文档,当使用基于注释的配置时,对于 @Bean

destroyMethod
字段,Spring 的默认行为是在应用程序上下文正在运行时自动调用名为
close
shutdown
的公共、无参数方法。关闭。

为了方便用户,容器将尝试推断 destroy 方法针对从 @Bean 方法返回的对象。为了 例如,给定一个返回 Apache Commons DBCP 的 @Bean 方法 BasicDataSource,容器会注意到close()方法 在该对象上可用并自动将其注册为 销毁方法。这种“破坏方法推断”目前仅限于 仅检测名为“close”或“shutdown”的公共、无参数方法。这 方法可以在继承层次结构的任何级别声明,并且 无论 @Bean 方法的返回类型如何,都会被检测到 (即,检测是针对 bean 实例本身反射发生的 在创建时)。

重申一下,当未显式设置销毁方法时,这是“注释驱动”配置的默认行为。如果不需要这种行为,则显式将 destroy 方法设置为空字符串将禁用此“功能”:

要禁用特定@Bean的销毁方法推断,请指定一个 空字符串作为值,例如@Bean(destroyMethod="")。请注意, DisposableBean 和 Closeable/AutoCloseable 接口将 尽管如此,还是会被检测到并使用相应的销毁/关闭方法 被调用。

另一方面,当使用 XML 配置时,这
不是

默认行为...为了实现奇偶校验,destroy-method 可以显式设置为 (inferred)。有关详细信息,请参阅官方文档中的

销毁回调
默认初始化和销毁方法部分。


1
投票
http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html


1
投票
@Keith 的答案

@Bean("fixedThreadPool") public ExecutorService fixedThreadPool() { return Executors.newFixedThreadPool(THREAD_POOL_SIZE); }



0
投票
@PreDestroy

注释:

@PreDestroy
@SneakyThrows
void shutdownExecutor() {
  executor.shutdown();
  if (!executor.awaitTermination(1, TimeUnit.SECONDS)) {
    executor.shutdownNow();
  }
}

© www.soinside.com 2019 - 2024. All rights reserved.