从动态创建的持久Quartz作业

时间:2017-05-16 09:08:30

标签: spring spring-boot quartz-scheduler

Spring Boot 1.5

Quartz 2.2

我在运行时使用Quartz配置为jdbc-job-store动态创建和调度Quartz作业。这些工作需要在应用程序执行之间保持不变。 在作业执行期间,我需要访问完整的Spring上下文(Spring管理的bean和JPA事务)。

然而,如果我尝试将任何东西自动装入我的工作中,那么我会收到类似的错误。 "通过字段myAutowiredField"

表示的不满意的依赖性

我无法解决这个问题。我发现很多人都展示了如何让自动装配工作在Quartz工作中,但几乎所有这些工作都只有一个静态的,硬编码的工作。不是在运行时动态创建的作业。

以下网址的示例最接近。它可动态创建作业,并且自动装配功能非常出色。但是,它是一家公羊店。一旦我切换到jdbc,我就回到原点。

https://icecarev.com/2016/11/05/spring-boot-1-4-and-quartz-scheduling-runtime-created-job-instances-from-a-configuration-file/

我也看过这些..

Spring + Hibernate + Quartz: Dynamic Job

inject bean reference into a Quartz job in Spring?

......等等。

但同样,他们的解决方案似乎都缺少了一些东西。例如,他们依赖于静态工作,触发器,或者只是简单地工作等等。

任何人都有关于最新资源的提示或链接?

谢谢!

修改1

当工作被解雇时,弹簧上下文会发生一些事情。这里有一些代码可以说明。

在第一次autowireBean()调用中(这是在Spring Boot配置期间完成的),它不会抛出错误。注意:在这一点上,没有用处,我只是表明它确实工作了#39;这里。

在第二次autowireBean()调用中(这是触发作业的时候),它失败了。这是真实的'调用

public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory
{

    private transient AutowireCapableBeanFactory beanFactory;



    public AutowiringSpringBeanJobFactory(ApplicationContext context)
    {
        super();
        this.beanFactory = context.getAutowireCapableBeanFactory();

        MyJobClass job = new MyJobClass();
        beanFactory.autowireBean(new MyJobClass()); /** no problem **/
        beanFactory.initializeBean(job, "job");

    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception 
    {
        final Object job = super.createJobInstance(bundle); /* job is an instance MyJobClass.. same as above */
        beanFactory.autowireBean(job); /** "Unsatisfied dependency" exception **/
        beanFactory.initializeBean(job, "job");
        return job;
    }
}

修改2

好吧,我似乎已经开始工作,但是,我不知道是否会有后果。 这是org.springframework.scheduling.quartz.AdaptableJobFactory

的罪魁祸首
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
    return bundle.getJobDetail().getJobClass().newInstance();
}

似乎bundle.getJobDetail()。getJobClass()返回了一些' proxy'我的工作类的类型。但基本上它'说'它返回了我正确的Job课程,但情况有所不同。它有相同的名称,但我无法施展它。例如......

Object job = bundle.getJobDetail().getJobClass().newInstance();
MyJobClass myJob = (MyJobClass) job;

引发错误,说我无法将com.company.MyJobClass转换为com.company.MyJobClass。

所以这里是我的修复' ...

@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception 
{
    String className = bundle.getJobDetail().getJobClass().getName();
    Object job = Class.forName(className).newInstance();
    beanFactory.autowireBean(job);
    job = beanFactory.applyBeanPostProcessorsAfterInitialization(job, "job");  // Without this, @Transactional in my job bean doesn't work
    beanFactory.initializeBean(job, "job");
    return job;
}

由于我不再调用super(),我失去了SpringBeanJobFactory的一个方便功能,但我暂时还不错。 我想底线是需要在这个sucker包装在事务代理中之前调用autowireBean()。

1 个答案:

答案 0 :(得分:0)

当你提到"不是在运行时动态创建的作业。"我会假设你在某些时候做了类似的事情:MyJob job = new MyJob();

如果您想使用Spring' @Autowire在MyJob中注入依赖项,我想到的一种方法是:

  • 使用:@Configurable(dependencyCheck = true)
  • 注释MyJob类
  • 使用Java代理运行Java进程:java -javaagent:<path to spring-agent-${spring.version}.jar> ...