9

看来我们使用 Quartz - JDBCJobStore 以及 Spring、Hibernate 和 Websphere 的实现正在抛出非托管线程。

我做了一些阅读,发现 IBM 的一篇技术文章指出使用 Quartz 和 Spring 会导致这种情况。他们建议使用 CommnonJ 来解决这个问题。

我做了一些进一步的研究,到目前为止我看到的唯一例子都是处理不在数据库中的旧 JobStore 计划。

所以,我想知道是否有人有这个问题的解决方案的例子。

谢谢

4

8 回答 8

10

我们有一个可行的解决方案(实际上是两个)。

1) 更改石英源代码以将 WorkManager 守护线程用于主调度程序线程。它有效,但需要更换夸脱。不过我们没有使用这个,因为我们不想维护一个被破解的石英版本。(这提醒了我,我打算将这个提交给项目但完全忘记了)

2) 创建一个 WorkManagerThreadPool 用作石英线程池。实现quartz ThreadPool 的接口,以便在quartz 中触发的每个任务都包装在一个commonj Work 对象中,然后该对象将在WorkManager 中调度。关键是 WorkManagerThreadPool 中的 WorkManager 必须在调度程序启动之前从 Java EE 线程(例如 servlet 初始化)初始化。然后 WorkManagerThreadPool 必须创建一个守护线程,该线程将通过创建和调度新的 Work 对象来处理所有已调度的任务。这样,调度程序(在它自己的线程上)将任务传递给托管线程(工作守护进程)。

不简单,不幸的是我没有现成的可包含的代码。

于 2008-10-07T14:06:00.130 回答
7

为线程添加另一个答案,因为我终于找到了解决方案。

我的环境:WAS 8.5.5,Quartz 1.8.5,没有 Spring。

我遇到的问题是(上述)非托管线程导致 NamingException ctx.lookup(myJndiUrl),而是在其他应用程序服务器(JBoss,Weblogic)中正确工作;实际上,Webpshere 正在触发一个带有以下消息的“事件”:

javax.naming.ConfigurationException:无法完成对“java:”名称的 JNDI 操作,因为服务器运行时无法将该操作的线程与任何 J2EE 应用程序组件相关联。当使用“java:”名称的 JNDI 客户端未在服务器应用程序请求的线程上执行时,可能会发生这种情况。确保 J2EE 应用程序不会在静态代码块或由该 J2EE 应用程序创建的线程中对“java:”名称执行 JNDI 操作。此类代码不一定在服务器应用程序请求的线程上运行,因此不受“java:”名称上的 JNDI 操作的支持。

以下步骤解决了该问题:

1) 升级到quartz 1.8.6(没有代码更改),只是maven pom

2) 将以下 dep 添加到类路径(在我的例子中,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,请参阅WAS 控制台中的Resources -> AsynchronousBeans -> WorkManagers ):

org.quartz.threadExecutor.class=org.quartz.custom.WorkManagerThreadExecutor
org.quartz.threadExecutor.workManagerName=wm/default

注意:正确的类是org.quartz。用于quartz-scheduler-1.8.6(已测试)或org.quartz的自定义.WorkManagerThreadExecutor 。commonj .WorkManagerThreadExecutor2.1.1开始(未经测试,但在 maven 的 repos 上的实际quartz-commonj 的 jar中验证)

4)在石英作业的空构造函数中 移动了JNDI 查找(感谢m_klovre 的“J2EE 容器外的线程”);也就是说,构造函数是newInstance()从我的应用程序的同一个 J2EE 上下文中通过反射(方法)调用的,并且可以访问java:global命名空间,而该execute(JobExecutionContext)方法仍在较差的上下文中运行,它缺少我的应用程序的所有 EJB

希望这可以帮助。

附言。作为参考,您可以在此处找到我在上面使用的 quartz.properties 文件的示例

于 2013-07-19T09:16:21.983 回答
3

检查这篇文章: http ://www.ibm.com/developerworks/websphere/techjournal/0609_alcott/0609_alcott.html

基本上,将 SchedulerFactoryBean 上的 taskExecutor 属性设置为使用 org.springframework.scheduling.commonj.WorkManager TaskExecutor ,它将使用容器管理的线程。

于 2008-12-08T15:23:40.433 回答
2

请注意:上述 QUARTZ-708 的链接不再有效。这个新问题(在新的 Jira 中)似乎正在解决这个问题:http ://jira.terracotta.org/jira/browse/QTZ-113 (fixVersion = 1.8.6, 2.0.2)

于 2013-07-18T08:45:06.490 回答
2

我最近遇到了这个问题。实际上你需要:

  1. 通过将工作委派给 Websphere Work Manager 来实现线程池。(Quartz 仅提供在非托管线程上运行作业的 SimpleThreadPool)。org.quartz.threadPool.class通过属性告诉quartz使用这个线程池
  2. 通过属性告诉石英使用WorkManagerThreadExecutor(或实现自定义)org.quartz.threadExecutor.class
  3. 对繁琐的遗留 Web 容器有点耐心 :)

这是使用 Quartz 和 Websphere(以及 Tomcat)的g​​ithub 演示。

希望它可以帮助某人..

于 2017-05-04T21:30:52.637 回答
1

您可以查看以下关于石英的 JIRA 链接。

http://jira.opensymphony.com/browse/QUARTZ-708

这具有所需的 WebSphereThreadPool 实现,可以与上述的quartz.properties 中的更改一起使用以满足您的要求。希望这可以帮助。

问候,湿婆

于 2009-09-22T13:10:10.097 回答
1

您将不得不使用 websphere 的托管线程池。你可以通过 spring 和 commonj 做到这一点。CommonJ 可以有一个任务执行器来创建托管线程。您甚至可以使用对 jndi 托管线程资源的引用。然后,您可以将 commonj 任务执行器注入基于 Spring 的 Quartz SchedulerFactoryBean。

请参阅http://open.bekk.no/boss/spring-scheduling-in-websphere/并滚动到“Quartz with CommonJ”部分了解更多详细信息。

于 2010-10-15T21:12:09.470 回答
1

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 的答案”出现,而不是作为主题的答案。找不到区分这些的方法。)

于 2013-07-22T15:10:48.197 回答