我可以将 CDI 注入到quartz调度程序作业中吗?

发布于 2024-10-14 11:52:06 字数 1717 浏览 6 评论 0原文

我使用 Glassfish 和 CDI 进行注射,(大部分)成功。我似乎无法让 Quartz 作业与注入一起使用 - 用 @Inject 注释的 bean 永远不会被注入。

Quartz 是否使用某种不同的类加载器来防止注入发生?

我在 web.xml 中像这样配置 Quartz:

<context-param>
    <param-name>quartz:config-file</param-name>
    <param-value>quartz.properties</param-value>
</context-param>
<context-param>
    <param-name>quartz:shutdown-on-unload</param-name>
    <param-value>true</param-value>
</context-param>
<context-param>
    <param-name>quartz:wait-on-shutdown</param-name>
    <param-value>false</param-value>
</context-param>
<context-param>
    <param-name>quartz:start-scheduler-on-load</param-name>
    <param-value>true</param-value>
</context-param>

<listener>
    <listener-class>
        org.quartz.ee.servlet.QuartzInitializerListener
    </listener-class>
</listener>

我的quartz.properties 看起来像:

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = 1
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false

org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml
org.quartz.plugin.jobInitializer.scanInterval = 10
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
org.quartz.plugin.jobInitializer.failOnFileNotFound = true

I'm using Glassfish and CDI for injection, (mostly) successfully. I can't seem to get Quartz jobs to work with injection- beans annotated with @Inject never get injected.

Is Quartz using some kind of different classloader that's preventing injection from happening?

I'm configuring Quartz like so in my web.xml:

<context-param>
    <param-name>quartz:config-file</param-name>
    <param-value>quartz.properties</param-value>
</context-param>
<context-param>
    <param-name>quartz:shutdown-on-unload</param-name>
    <param-value>true</param-value>
</context-param>
<context-param>
    <param-name>quartz:wait-on-shutdown</param-name>
    <param-value>false</param-value>
</context-param>
<context-param>
    <param-name>quartz:start-scheduler-on-load</param-name>
    <param-value>true</param-value>
</context-param>

<listener>
    <listener-class>
        org.quartz.ee.servlet.QuartzInitializerListener
    </listener-class>
</listener>

My quartz.properties looks like:

org.quartz.scheduler.instanceName = MyScheduler
org.quartz.scheduler.instanceId = 1
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false

org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 3

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz-config.xml
org.quartz.plugin.jobInitializer.scanInterval = 10
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false
org.quartz.plugin.jobInitializer.failOnFileNotFound = true

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小ぇ时光︴ 2024-10-21 11:52:06

我查看了@george-armhold提到的github库,但发现它并不成熟。

尽管如此,我找到了另一个解决方案。

查看此博客文章:DevSoap:将 CDI 托管 Bean 注入石英作业。它描述了一个类 CdiJobFactory.java,它将完成这项工作(用 Groovy 或 Scala 编写,但不是 kotlin 或 java)。

中实现

在支持 CDI 的作业工厂

Java 中的相同 CdiJobFactory:

/**
 * CDI Job factory. Quartz will produce CDI managed beans.
 */
@ApplicationScoped
public class CdiJobFactory implements JobFactory {

  @Inject
  BeanManager beanManager;

  @Override
  public Job newJob(final TriggerFiredBundle bundle, final Scheduler scheduler) throws SchedulerException {
    final Class<Job> jobClazz = (Class<Job>) bundle.getJobDetail().getJobClass();
    final Bean<Job> bean = (Bean<Job>) beanManager.getBeans(jobClazz).stream().findAny().orElseThrow(IllegalStateException::new);
    final CreationalContext<Job> ctx = beanManager.createCreationalContext(bean);

    return (Job) beanManager.getReference(bean, jobClazz, ctx);
  }

}

在侦听器类中注入 CDI 作业工厂

现在,在将在启动时加载的侦听器类中,执行以下操作:

@ApplicationScoped
public class Listener implements ServletContextListener {

  @Inject
  public Listener(final CdiJobFactory jobFactory) {
    this.jobFactory = jobFactory;
  }

  @Override
  public void contextInitialized(final ServletContextEvent servletEvent) {
    LOG.info("Initializing Listener");

    try {
      scheduler = StdSchedulerFactory.getDefaultScheduler();
      scheduler.setJobFactory(jobFactory);
    } catch (final SchedulerException | RuntimeException schedEx) {
      LOG.error("Problem loading Quartz!", schedEx);
    }

   // register your jobs here
  }
}

创建作业

再次查看博客文章。只需用 @Dependent@ApplicationScoped (取决于您的用例)注释它们就可以了。

不要忘记创建两个构造函数:一个公共无参数构造函数和一个用 @Inject 注释的公共构造函数以及所需的 bean 作为参数。为了简洁起见,我提到了第一个构造函数。

如果您要使用 needle4j 进行测试,则只会使用注释为 @Inject 的字段来获取注入。但你可以两者兼得,焊接不会抱怨。

其他替代方案

您还可以查看 Apache Deltaspike。它还将处理其他 CDI 实现。如果您在具有不同实现的各种应用程序服务器上运行应用程序(例如 JBoss、Websphere、Liberty Profile、TomEE、Glassfish 等),这非常有用。

I looked into the github library mentioned by @george-armhold, but found it not mature.

Nevertheless, I found another solution.

Take a look into this blog post: DevSoap: Injecting CDI Managed Beans into Quartz Jobs. It describes a class CdiJobFactory.java, which will do the job (written in either Groovy or Scala, but not kotlin or java).

Implementation in java

CDI-capable Job Factory

Same CdiJobFactory in java:

/**
 * CDI Job factory. Quartz will produce CDI managed beans.
 */
@ApplicationScoped
public class CdiJobFactory implements JobFactory {

  @Inject
  BeanManager beanManager;

  @Override
  public Job newJob(final TriggerFiredBundle bundle, final Scheduler scheduler) throws SchedulerException {
    final Class<Job> jobClazz = (Class<Job>) bundle.getJobDetail().getJobClass();
    final Bean<Job> bean = (Bean<Job>) beanManager.getBeans(jobClazz).stream().findAny().orElseThrow(IllegalStateException::new);
    final CreationalContext<Job> ctx = beanManager.createCreationalContext(bean);

    return (Job) beanManager.getReference(bean, jobClazz, ctx);
  }

}

Injection of CDI Job Factory in your listener classes

Now in your Listener class which will load on startup, do this:

@ApplicationScoped
public class Listener implements ServletContextListener {

  @Inject
  public Listener(final CdiJobFactory jobFactory) {
    this.jobFactory = jobFactory;
  }

  @Override
  public void contextInitialized(final ServletContextEvent servletEvent) {
    LOG.info("Initializing Listener");

    try {
      scheduler = StdSchedulerFactory.getDefaultScheduler();
      scheduler.setJobFactory(jobFactory);
    } catch (final SchedulerException | RuntimeException schedEx) {
      LOG.error("Problem loading Quartz!", schedEx);
    }

   // register your jobs here
  }
}

Creating jobs

Look again at the blog post. Just annotate them with @Dependent or @ApplicationScoped (depending on your use case) and you are fine.

Don't forget to create two constructors: A public no-arg constructor and a public constructor annotated with @Inject and the needed beans as parameters. I omnited the first constructor for brevity.

If you are going to test with needle4j, injections will only get picked up with a field annotated @Inject. But you can have both, weld won't complain.

Other alternatives

You can also take a look at Apache Deltaspike. It will also handle other CDI implementations. This is useful if you run your application on various application servers with different implementations (like JBoss, Websphere, Liberty Profile, TomEE, Glassfish, etc.).

我的痛♀有谁懂 2024-10-21 11:52:06

您将需要自己实现 org.quartz.spi.JobFactory,它知道如何使用应用程序的 CDI 来实例化作业类并注入它们。

You will need to make your own implementation of org.quartz.spi.JobFactory that knows how to use your application's CDI to instantiate the jobs classes and inject them.

瘫痪情歌 2024-10-21 11:52:06

github 上有一个 Quartz CDI 集成库。还没试过。

There is a Quartz CDI integration library on github. Have not tried it yet.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文