can I use CDI injection into quartz-scheduler jobs?

左心房为你撑大大i 提交于 2019-12-05 20:27:26

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.

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.).

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!