Tomcat webapp中的Spring ThreadPoolTask​​Executor - 糟糕的做法?

doa*_*hai 8 spring tomcat threadpool

最近在我的项目中,我需要异步执行一些任务.由于我们在Tomcat中运行带有Spring的webapp,因此Spring提供的ThreadPoolTask​​Executor是一个解决方案.

然而,架构师提出了一些反对意见,声称产生线程/在webapp中有一个线程池是可怕/禁止/绝对邪恶.

通过在网上和StackOverflow上搜索一下,我意识到是的,在Java EE容器中拥有自己的线程池是一种不好的做法.理由是,如果您拥有自己的线程池,则容器不会意识到它并且无法正确管理资源.当您需要对Web应用程序进行一些热部署时,这一点尤其重要.

现在,我们的用例是在Tomcat中运行的Spring webapp.首先,我们可以将Spring容器视为轻量级 Java EE容器吗?在这种情况下,Spring是直接管理线程池生命周期而不是应用程序本身,不是吗?

其次,热部署参数是否也适用于此配置?

是的,我知道可以直接在Tomcat中声明一个工作池,并通过JNDI将它注入Spring.但与Spring提供的直接ThreadPoolTask​​Executor工具相比,这有点麻烦

所以我的最后一个问题是:在我的案例中,建筑师的反对意见是什么?

感谢您对此主题的建议和想法.

Arj*_*jms 10

有各种各样的邪恶,并不是所有的邪恶在每种情况下都被视为邪恶.

按需创建线程而不是使用池通常被认为是邪恶的,但对于Java EE而言,这不仅适用于几乎任何类型的服务器应用程序.

在Java EE中,EJB容器中特别不允许创建自己的线程.这是因为Java EE容器可能无形地将上下文数据存储在线程本地存储中,如果代码在其自己的线程中开始执行,则会丢失.

然而,Web容器没有这样的限制,根据规范,拥有线程池或多或少是合法的.这就是人们过去常常从EAR中的Web模块启动Quartz的原因,即使只使用了EJB模块,或者为什么Web模块中的代码可以将回调侦听器注册到非托管JMS队列,但是EJB不能做这个.

但是,实际上创建线程(通过池)实际上几乎总能工作,只要你记住,如果你使用例如EJB,你需要在这些线程中运行的代码中从JNDI获取实例,而不传递EJB的引用那些不受管理的线程.当然,您需要注意关闭池,但Java EE中的几乎所有类型的启动侦听器都有相应的关闭侦听器,您可以在其中执行此操作.

Java EE确实有一些官方方法可以减少创建自己的池的需要:

然而,一些算法需要单独的线程池以防止死锁的可能性.由于没有任何Java EE解决方案能够绝对保证工作由不同的线程池完成,因此有时候除了创建自己的池之外没有其他合理的方法.

因此,在最后一种情况下,将代码打开到死锁实际上比创建自己的线程池更邪恶.


Mar*_*ius 2

恕我直言,如果正确隔离的话,在 Java EE 应用程序中拥有自我管理的 TaskExecutors 并不是一个坏习惯。将异步任务分离到独立的实例中会带来新的复杂性、新的依赖关系并降低性能。

不受管理的架构师参数当然可以为空,因为容器不知道/许多实例的所有者(例如静态引用),并且您可以在 @Configuration 类中或 spring 配置文件中配置执行器本身,如下所示至少执行器本身由容器管理。

此外,Spring本身公开了几种执行调度方法的方法,例如通过使用@Scheduled注释(http://static.springsource.org/spring/docs/3.0.x/reference/scheduling.html)

热部署依赖项取决于工作队列的配置方式以及异步任务处理它们的方式。