之前做的一个项目用到quartz框架进行定时任务的开发。由于定时任务的job类中需要调用其他service的方法,所以必须注入需要的bean。但是在运行项目的时候发现,job类中的依赖注入会报空指针异常。于是从网上查了相关资料,以解决这个问题。
quartz有三个核心概念:调度器、任务和触发器。三者关系是,调度器负责调度各个任务,到了某个时刻或者过了一定时间,触发器触动了,特定任务便启动执行。概念相对应的类和接口有:
在quartz框架中,Job 是通过反射出来的实例,不受spring的管理。Scheduler现在交给Spring生成,在Spirng-context-support jar包下org.springframework.scheduling.quartz包中有个SpringBeanJobFactory的类,job实例通过该类的createJobInstance方法创建。根据Scheduler context、job data map and trigger data map填充其属性。但是创建的job实例并没被spring管理,这就需要我们自定义一个类将创建的job添加到applicationContext中,该类需要继承SpringBeanJobFactory,并实现ApplicationContextAware接口。
ApplicationContextAware接口的作用:Spring容器会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该Bean的setApplicationContextAware()方法,调用该方法时,会将容器本身作为参数传给该方法——该方法中的实现部分将Spring传入的参数(容器本身)赋给该类对象的applicationContext实例变量,因此接下来可以通过该applicationContext实例变量来访问容器本身。
重写SpringBeanJobFactory类中的createJobInstance方法,将创建的job实例添加到applicationContext中,交给spring管理。
代码如下:
public final class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements
ApplicationContextAware {
private transient AutowireCapableBeanFactory autowireCapablebeanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
autowireCapablebeanFactory= context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
autowireCapablebeanFactory.autowireBean(job);
return job;
}
}
再将AutowiringSpringBeanJobFactory交给spring管理,job类中依赖注入空指针问题就解决了
@Configuration
public class SchedulerConfig {
@Bean
public JobFactory jobFactory(ApplicationContext applicationContext)
{
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory) throws Exception {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setOverwriteExistingJobs(true);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
factory.afterPropertiesSet();
return factory;
}
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
}
**本人能力有限,如果有什么错误还望大家及时纠正,一定会虚心接受,共同进步。