我可以将CDI注入到quartz-scheduler工作中吗?

时间:2011-01-27 04:36:55

标签: dependency-injection glassfish quartz-scheduler glassfish-3 cdi

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

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

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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

然而,我找到了另一种解决方案。

请查看此博文:DevSoap: Injecting CDI Managed Beans into Quartz Jobs。它描述了一个类CdiJobFactory.java,它将完成这项工作(用Groovy或Scala编写,但不能用kotlin或java编写)。

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作业工厂

现在,在启动时加载的Listener类中,执行以下操作:

@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等),这将非常有用。

答案 2 :(得分:0)

github上有一个Quartz CDI集成库。尚未尝试过。