Java 如何使用 Spring 正确关闭执行程序服务?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18516131/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to properly shutdown executor services with Spring?
提问by Giovanni Botta
I have a command line application that uses a Spring-managed bean that's composed of a java ExecutorService
created with:
我有一个命令行应用程序,它使用一个 Spring 管理的 bean,该 bean 由一个 java 组成,使用以下命令ExecutorService
创建:
ExecutorService service = Executors.newFixedThreadPool(4);
Now, I want my service to shutdown when my application shuts down, so I made my bean implement the DisposableBean
interface and have a destroy method such as:
现在,我希望我的服务在我的应用程序关闭时关闭,所以我让我的 bean 实现了DisposableBean
接口并有一个销毁方法,例如:
public void destroy(){
service.shutdown();
}
Then I might be tempted to do something like register a shutdown hook on the Spring context. However I found out (the hard way, i.e., in a pre-production release) that this doesn't work: the shutdown hook doesn't get called before the ExecutorService.shutdown()
method is called, causing a classic catch 22 problem (it does get called on interruption, i.e., if I hit Ctrl-C while the application is running). This escaped my unit tests because for some reason it seems to work fine from within JUnit, which is still puzzling me: what does JUnit do differently?
然后我可能会想做一些事情,比如在 Spring 上下文中注册一个关闭钩子。但是我发现(困难的方法,即在预生产版本中)这不起作用:在调用ExecutorService.shutdown()
方法之前不会调用关闭挂钩,从而导致经典的 catch 22 问题(它确实被调用中断时,即,如果我在应用程序运行时按 Ctrl-C)。这逃脱了我的单元测试,因为出于某种原因,它在 JUnit 中似乎可以正常工作,这仍然让我感到困惑:JUnit 有何不同?
The solution I found so far is to explicitly call ApplicationContext.close()
right before I exit my main function. I was wondering if there was a better solution to this and what are the best practices for having flexible thread pools managed by Spring. Also what if my bean is notdirectly managed by Spring but is created by a bean managed by Spring? Should I just cascade the calls to destroy()
? Wouldn't this be very error prone?
到目前为止,我找到的解决方案是ApplicationContext.close()
在退出主函数之前显式调用。我想知道是否有更好的解决方案,以及由 Spring 管理的灵活线程池的最佳实践是什么。另外,如果我的 bean不是由 Spring 直接管理而是由 Spring 管理的 bean 创建的怎么办?我应该将调用级联到destroy()
吗?这不会很容易出错吗?
I appreciate any comments, suggestions, further reading, RTFMs, magic recipes.
我感谢任何评论、建议、进一步阅读、RTFM、魔法食谱。
Thanks!
谢谢!
采纳答案by Keith
Are you aware that this:
你知道吗:
ExecutorService service = Executors.newFixedThreadPool(4);
can be replaced with this:
可以用这个替换:
<bean id="service" class="java.util.concurrent.Executors"
factory-method="newFixedThreadPool" destroy-method="shutdown">
<constructor-arg value="4"/>
</bean>
The spring context then manages, more directly, the shutdown of your executor service--and it can be more easily reused.
然后,spring 上下文更直接地管理执行程序服务的关闭——并且可以更轻松地重用它。
回答by aweigold
Consider using Spring's TaskExecutor, which can be configured with a thread pool. http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html
考虑使用Spring的TaskExecutor,可以配置线程池。 http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html
回答by Andrey
Per official Spring documentation, when using annotation-based configuration, for destroyMethodfield of @Bean
, Spring's default behavior is to automatically invoke public, no-arg methods named close
or shutdown
when the application context is being closed.
根据官方 Spring 文档,当使用基于注解的配置时,对于destroyMethod字段@Bean
,Spring 的默认行为是自动调用已命名的公共、无参数方法close
或shutdown
在关闭应用程序上下文时。
As a convenience to the user, the container will attempt to infer a destroy method against an object returned from the @Bean method. For example, given an @Bean method returning an Apache Commons DBCP BasicDataSource, the container will notice the close() method available on that object and automatically register it as the destroyMethod. This 'destroy method inference' is currently limited to detecting only public, no-arg methods named 'close' or 'shutdown'. The method may be declared at any level of the inheritance hierarchy and will be detected regardless of the return type of the @Bean method (i.e., detection occurs reflectively against the bean instance itself at creation time).
为方便用户,容器将尝试针对从@Bean 方法返回的对象推断销毁方法。例如,给定返回 Apache Commons DBCP BasicDataSource 的 @Bean 方法,容器将注意到该对象上可用的 close() 方法并自动将其注册为 destroyMethod。这种“破坏方法推断”目前仅限于检测名为“close”或“shutdown”的公共、无参数方法。该方法可以在继承层次结构的任何级别声明,并且无论@Bean 方法的返回类型如何,都会被检测到(即,检测在创建时反射地针对 bean 实例本身发生)。
To re-iterate, this is the default behavior for annotation-drivenconfiguration when a destroy method is not explicitly set. If this behavior is undesired explicitly setting destroy method to an empty string will disable this "feature":
重申一下,当未明确设置 destroy 方法时,这是注释驱动配置的默认行为。如果不希望出现此行为,将 destroy 方法显式设置为空字符串将禁用此“功能”:
To disable destroy method inference for a particular @Bean, specify an empty string as the value, e.g. @Bean(destroyMethod=""). Note that the DisposableBean and the Closeable/AutoCloseable interfaces will nevertheless get detected and the corresponding destroy/close method invoked.
要禁用特定@Bean 的销毁方法推理,请指定一个空字符串作为值,例如@Bean(destroyMethod="")。请注意,仍然会检测到 DisposableBean 和 Closeable/AutoCloseable 接口并调用相应的 destroy/close 方法。
On the other hand, when using XML configuration, this is notthe default behavior... To achieve parity, destroy-methodcan be explicitly set to (inferred)
. Refer to the Destruction callbacksand Default initialization and destroy methodssections in the official docs for details.
另一方面,当使用 XML 配置时,这不是默认行为......要实现奇偶校验,可以将destroy-method显式设置为(inferred)
。有关详细信息,请参阅官方文档中的销毁回调和默认初始化和销毁方法部分。