非托管线程 Spring Quartz Websphere Hibernate
看来我们使用 Quartz - JDBCJobStore 以及 Spring、Hibernate 和 Websphere 的实现会引发非托管线程。
我读了一些书,发现 IBM 的一篇技术文章指出,将 Quartz 与 Spring 一起使用会导致这种情况。 他们建议使用 CommnonJ 来解决这个问题。
我做了一些进一步的研究,到目前为止我看到的唯一示例都涉及不在数据库中的计划旧 JobStore。
所以,我想知道是否有人有解决此问题的示例。
谢谢
It appears that our implementation of using Quartz - JDBCJobStore along with Spring, Hibernate and Websphere is throwing unmanaged threads.
I have done some reading and found a tech article from IBM stating that the usage of Quartz with Spring will cause that. They make the suggestion of using CommnonJ to address this issue.
I have done some further research and the only examples I have seen so far all deal with the plan old JobStore that is not in a database.
So, I was wondering if anyone has an example of the solution for this issue.
Thanks
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我们对此有一个可行的解决方案(实际上是两个)。
1) 更改quartz源代码以使用WorkManager守护线程作为主调度程序线程。 它可以工作,但需要更换夸脱。 但我们没有使用它,因为我们不想维护石英的黑客版本。 (这提醒了我,我本来打算将其提交给项目,但完全忘记了)
2)创建一个 WorkManagerThreadPool 用作石英线程池。 实现quartz ThreadPool 的接口,以便quartz 中触发的每个任务都包装在一个commonj Work 对象中,然后该对象将在WorkManager 中进行调度。 关键是 WorkManagerThreadPool 中的 WorkManager 必须在调度程序启动之前从 Java EE 线程初始化(例如 servlet 初始化)。 然后,WorkManagerThreadPool 必须创建一个守护线程,该线程将通过创建和调度新的 Work 对象来处理所有计划任务。 这样,调度程序(在其自己的线程上)将任务传递给托管线程(工作守护进程)。
并不简单,不幸的是我没有现成的代码可供包含。
We have a working solution for this (two actually).
1) Alter the quartz source code to use a WorkManager daemon thread for the main scheduler thread. It works, but requires changing quarts. We didn't use this though since we didn't want maintain a hacked version of quartz. (That reminds me, I was going to submit this to the project but completely forgot)
2) Create a WorkManagerThreadPool to be used as the quartz threadpool. Implement the interface for the quartz ThreadPool, so that each task that is triggered within quartz is wrapped in a commonj Work object that will then be scheduled in the WorkManager. The key is that the WorkManager in the WorkManagerThreadPool has to be initialized before the scheduler is started, from a Java EE thread (such as servlet initialization). The WorkManagerThreadPool must then create a daemon thread which will handle all the scheduled tasks by creating and scheduling the new Work objects. This way, the scheduler (on its own thread) is passing the tasks to a managed thread (the Work daemon).
Not simple, and unfortunately I do not have code readily available to include.
添加另一个答案到线程中,因为我终于找到了解决方案。
我的环境:WAS 8.5.5,Quartz 1.8.5,无 Spring。
我遇到的问题是(上述)非托管线程导致
ctx.lookup(myJndiUrl)
出现 NamingException,而该线程在其他应用程序服务器(JBoss、Weblogic)中正常工作); 实际上,Webpshere 正在引发一个“事件”,并显示以下消息:以下步骤解决了该问题:
1) 已升级到quartz 1.8.6(没有代码更改),只需 maven pom
2) 将以下 dep 添加到类路径(在我的例子中,EAR 的 /lib 文件夹),以使新的 WorkManagerThreadExecutor 可用
注意:在 < a href="http://jira.terracotta.org/jira/browse/QTZ-113" rel="nofollow">QTZ-113 或官方 Quartz 文档 1.x 2.x 没有提及如何激活此修复程序。
3) 在quartz.properties中添加了以下内容(“wm/default”是我的WAS 8.5.5中已配置的DefaultWorkManager的JNDI,请参阅Resources -> AsynchronousBeans -> WorkManagers 在 WAS 控制台中):
注意:对于quartz-scheduler-1.8.6(已测试),正确的类是 org.quartz.custom.WorkManagerThreadExecutor,或 org.quartz.commonj.WorkManagerThreadExecutor 从2.1.1开始(未经测试,但在实际quartz-commonj 的 jars 在 Maven 的仓库中)
4) 将 JNDI 查找移至quartz 作业的空构造函数(感谢 m_klovre 的“J2EE 容器外部的线程”); 也就是说,构造函数是通过反射(
newInstance()
方法)从我的应用程序的同一 J2EE 上下文中调用的,并且可以访问java:global
命名空间,而execute(JobExecutionContext)
方法仍在较差的上下文中运行,该上下文缺少我的应用程序的所有 EJB希望这会有所帮助。
诗。 作为参考,您可以在此处找到我上面使用的quartz.properties 文件的示例
Adding another answer to the thread, since i found a solution for this, finally.
My environment: WAS 8.5.5, Quartz 1.8.5, no Spring.
The problem i had was the (above stated) unmanaged thread causing a NamingException from
ctx.lookup(myJndiUrl)
, that was instead correctly working in other application servers (JBoss, Weblogic); actually, Webpshere was firing an "incident" with the following message:The following steps solved the problem:
1) upgraded to quartz 1.8.6 (no code changes), just maven pom
2) added the following dep to classpath (in my case, EAR's /lib folder), to make the new WorkManagerThreadExecutor available
Note: in QTZ-113 or the official Quartz Documentation 1.x 2.x there's no mention on how to activate this fix.
3) added the following to quartz.properties ("wm/default" was the JNDI of the already configured DefaultWorkManager in my WAS 8.5.5, see Resources -> AsynchronousBeans -> WorkManagers in WAS console):
Note: right class is org.quartz.custom.WorkManagerThreadExecutor for quartz-scheduler-1.8.6 (tested), or org.quartz.commonj.WorkManagerThreadExecutor from 2.1.1 on (not tested, but verified within actual quartz-commonj's jars on maven's repos)
4) moved the JNDI lookup in the empty constructor of the quartz job (thanks to m_klovre's "Thread outside of the J2EE container"); that is, the constructor was being invoked by reflection (
newInstance()
method) from the very same J2EE context of my application, and had access tojava:global
namespace, while theexecute(JobExecutionContext)
method was still running in a poorer context, which was missing all of my application's EJBsHope this helps.
Ps. as a reference, you can find here an example of the quartz.properties file I was using above
检查这篇文章:
http://www.ibm.com/developerworks/websphere/techjournal/ 0609_alcott/0609_alcott.html
基本上,将 SchedulerFactoryBean 上的 taskExecutor 属性设置为使用 org.springframework.scheduling.commonj.WorkManager TaskExecutor ,它将使用容器管理的线程。
Check this article:
http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html
basically, set the taskExecutor property on SchedulerFactoryBean to use a org.springframework.scheduling.commonj.WorkManager TaskExecutor which will use container managed threads.
请注意:上述 QUARTZ-708 的链接不再有效。
这个新问题(在新的 Jira 中)似乎正在解决该问题:http://jira.terracotta.org/jira/browse/QTZ-113(修复版本 = 1.8.6、2.0.2)
Just a note: the above QUARTZ-708's link is not valid anymore.
This new issue (in a new Jira) seems to be addressing the problem: http://jira.terracotta.org/jira/browse/QTZ-113 (fixVersion = 1.8.6, 2.0.2)
我最近遇到了这个问题。 实际上您需要:
org.quartz.threadPool.class
属性告诉quartz使用这个线程池 通过WorkManagerThreadExecutor
(或者实现自定义一个) .class 属性这是 将 Quartz 与 Websphere(以及 Tomcat)结合使用的github 演示。
希望它可以帮助别人..
I have recently encountered this problem. Practically you need:
org.quartz.threadPool.class
propertyWorkManagerThreadExecutor
(or implement custom one) byorg.quartz.threadExecutor.class
propertyHere is github demo of using Quartz with Websphere (and also Tomcat).
Hope it helps someone..
您可以查看以下有关quartz 的 JIRA 链接。
http://jira.opensymphony.com/browse/QUARTZ-708
这有所需的 WebSphereThreadPool 实现可以与上述的quartz.properties 中的更改一起使用以满足您的要求。 希望这可以帮助。
问候,
湿婆
You can check the below JIRA link raised on quartz regarding this.
http://jira.opensymphony.com/browse/QUARTZ-708
This has the required WebSphereThreadPool implementation which can be used with the changes in quartz.properties as mentioned to meet your requirements. Hope this helps.
Regards,
Siva
您将必须使用 websphere 的托管线程池。 您可以通过 spring 和 commonj 来完成此操作。 CommonJ 可以有一个任务执行器来创建托管线程。 您甚至可以使用对 jndi 托管线程资源的引用。 然后,您可以将 commonj 任务执行器注入到基于 Spring 的 Quartz SchedulerFactoryBean 中。
请参阅http://open.bekk.no/boss/spring-scheduling- in-websphere/ 并滚动到“Quartz with CommonJ”部分以了解更多详细信息。
You will have to use websphere's managed thread pools. You can do this via spring and commonj. CommonJ can has a task executor that will create managed threads. You can even use a reference to a jndi managed thread resource. You can then inject the commonj task executor into the Spring based Quartz SchedulerFactoryBean.
Please see http://open.bekk.no/boss/spring-scheduling-in-websphere/ and scroll to "Quartz with CommonJ" section for more details.
PaoloC 针对 WAS85 和 Quartz 1.8.6 的提案也适用于 WAS80(和 Quartz 1.8.6),并且不需要 Spring。 (在我的设置中存在 Spring 2.5.5,但在该上下文中未使用。)
这样我就能够通过我自己的变体覆盖 SimpleJobFactory,使用 InjectionHelper 在每个新创建的作业上应用 CDI。 注入适用于@EJB(使用带注释的EJB远程业务接口的JNDI查找)和@Inject(首先使用新的InitialContext对CDI BeanManager进行JNDI查找,然后使用这个新获取的BM来查找CDI bean本身)。
谢谢 PaoloC 的回答! (我希望本文将作为“PaoloC 的答案”而不是主要主题的答案出现。没有找到区分它们的方法。)
The proposal from PaoloC for WAS85 ans Quartz 1.8.6 also works on WAS80 (and Quartz 1.8.6) and does not need Spring. (In my setup Spring 2.5.5 is present, but not in use in that context.)
That way I was able to override SimpleJobFactory by my own variant, using an InjectionHelper to apply CDI on every newly created job. Injection works for both @EJB (with JNDI lookup of the annotated EJB remote business interface) and @Inject (with JNDI lookup of the CDI BeanManager using a new InitialContext first, and then using this newly fetched BM to lookup the CDI bean itself).
Thank you PaoloC for that answer! (I hope this text will appear as an "answer to PaoloC" and not as an answer to the main topic. Found no way to differentiate between these.)