看来我们使用Quartz-JDBCJobStore以及Spring,Hibernate和Websphere的实现抛出了非托管线程。
我做了一些阅读,并发现了一篇来自IBM的技术文章,声称使用Quartz with Spring会导致这种情况。他们建议使用CommnonJ来解决这个问题。
我做了一些进一步的研究,到目前为止我见过的唯一例子都涉及不在数据库中的旧JobStore计划。
所以,我想知道是否有人有这个问题的解决方案的例子。
由于
答案 0 :(得分:10)
我们有一个可行的解决方案(实际上是两个)。
1)更改quartz源代码,以便为主调度程序线程使用WorkManager守护程序线程。它有效,但需要更改夸脱。我们没有使用它,因为我们不想保持一个黑客版本的石英。 (这提醒我,我打算将这个提交给项目,但完全忘了)
2)创建一个WorkManagerThreadPool用作石英线程池。实现石英ThreadPool的接口,以便在quartz中触发的每个任务都包装在一个commonj Work对象中,然后在WorkManager中进行调度。关键是WorkManagerThreadPool中的WorkManager必须在调度程序启动之前从Java EE线程(例如servlet初始化)初始化。然后,WorkManagerThreadPool必须创建一个守护程序线程,该线程将通过创建和计划新的Work对象来处理所有计划任务。这样,调度程序(在其自己的线程上)将任务传递给托管线程(Work守护程序)。
不简单,遗憾的是我没有随时可用的代码。
答案 1 :(得分:5)
在线程中添加另一个答案,因为我最终找到了解决方案。
我的环境:WAS 8.5.5,Quartz 1.8.5,没有Spring。
我遇到的问题是(上述)非托管线程导致来自ctx.lookup(myJndiUrl)
的NamingException,而是正确地在其他应用服务器中工作(JBoss,Weblogic);实际上,Webpshere正在通过以下消息发起“事件”:
javax.naming.ConfigurationException:无法完成对“java:”名称的JNDI操作,因为服务器运行时无法将操作的线程与任何J2EE应用程序组件相关联。当在服务器应用程序请求的线程上未执行使用“java:”名称的JNDI客户端时,可能会发生此情况。确保J2EE应用程序不对静态代码块中的“java:”名称或该J2EE应用程序创建的线程执行JNDI操作。此类代码不一定在服务器应用程序请求的线程上运行,因此JNDI对“java:”名称的操作不支持。
以下步骤解决了问题:
1)升级到石英1.8.6(无代码更改),只是maven pom
2)将以下dep添加到classpath(在我的情况下,EAR的/ lib文件夹中),以使新的WorkManagerThreadExecutor可用
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-commonj</artifactId>
<version>1.8.6</version>
</dependency>
注意:在QTZ-113或官方的Quartz文档1.x 2.x中,没有提及如何激活此修复程序。
3)将以下内容添加到quartz.properties(“wm / default”是我WAS 8.5.5中已配置的DefaultWorkManager的JNDI,请参阅 Resources - &gt; AsynchronousBeans - &gt; WAS控制台中的WorkManagers :
org.quartz.threadExecutor.class=org.quartz.custom.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default
注意:右侧类是 org.quartz。自定义 .WorkManagerThreadExecutor ,用于quartz-scheduler-1.8.6(已测试)或 org.quartz。<来自 2.1.1 的strong> commonj .WorkManagerThreadExecutor (未经过测试,但在maven's repos的实际quartz-commonj's jars内经过验证)
4)将 JNDI查找移动到石英作业的空构造函数(感谢m_klovre's "Thread outside of the J2EE container");也就是说,构造函数是通过反射(newInstance()
方法)从我的应用程序的同一个J2EE上下文中调用的,并且可以访问java:global
命名空间,而execute(JobExecutionContext)
方法仍在运行在较差的上下文中,它缺少我的所有应用程序的EJB
希望这有帮助。
聚苯乙烯。作为参考,你可以找到here我上面使用的quartz.properties文件的一个例子
答案 2 :(得分:3)
查看这篇文章: http://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html
基本上,在SchedulerFactoryBean上设置taskExecutor属性以使用org.springframework.scheduling.commonj.WorkManager TaskExecutor,它将使用容器管理的线程。
答案 3 :(得分:2)
请注意:以上QUARTZ-708的链接不再有效。 这个新问题(在一个新的Jira中)似乎正在解决这个问题:http://jira.terracotta.org/jira/browse/QTZ-113(fixVersion = 1.8.6,2.0.2)
答案 4 :(得分:1)
您可以查看以下有关此内容的石英上的JIRA链接。
http://jira.opensymphony.com/browse/QUARTZ-708
这具有必需的WebSphereThreadPool实现,可以与上面提到的quartz.properties中的更改一起使用,以满足您的要求。希望这会有所帮助。
此致 希瓦
答案 5 :(得分:1)
您必须使用websphere的托管线程池。你可以通过spring和commonj来做到这一点。 CommonJ可以有一个任务执行器来创建托管线程。您甚至可以使用对jndi托管线程资源的引用。然后,您可以将commonj任务执行程序注入基于Spring的Quartz SchedulerFactoryBean。
请参阅http://open.bekk.no/boss/spring-scheduling-in-websphere/并滚动到“Quartz with CommonJ”部分了解更多详情。
答案 6 :(得分:1)
PaoloC对WAS85和Quartz 1.8.6的提议也适用于WAS80(和Quartz 1.8.6),不需要Spring。 (在我的设置中,Spring 2.5.5存在,但在该上下文中没有使用。)
这样我就可以通过自己的变体覆盖SimpleJobFactory,使用InjectionHelper在每个新创建的作业上应用CDI。注入适用于@EJB(使用JNDI查找带注释的EJB远程业务接口)和@Inject(首先使用新的InitialContext对CDI BeanManager进行JNDI查找,然后使用这个新获取的BM来查找CDI bean本身)。
谢谢PaoloC的回答! (我希望这个文本将作为“PaoloC的答案”出现,而不是作为主题的答案。没有办法区分这些。)
答案 7 :(得分:0)
我最近遇到过这个问题。实际上你需要:
org.quartz.threadPool.class
property WorkManagerThreadExecutor
(或实现自定义的)org.quartz.threadExecutor.class
属性以下是使用Quartz和Websphere(以及Tomcat)的github demo。
希望它有所帮助..