Springboot自动注入scheduler
我们看下springboot官方文档(中文版,英文版我已经找不到quartz相关内容了):
Spring Boot 提供了几种使用 Quartz 调度器的便捷方式,它们来自 spring-boot-starter-quartz starter。如果 Quartz 可用,则 Spring Boot 将自动配置 Scheduler(通过 SchedulerFactoryBean 抽象)。
自动选取以下类型的 Bean 并将其与 Scheduler 关联起来:
- JobDetail:定义一个特定的 job。可以使用 JobBuilder API 构建 JobDetail 实例。
- Calendar。
- Trigger:定义何时触发 job。
从中我们可以看到,springboot已经自动为我们装填了scheduler,我们并不需要手动去创建。
同时,如果我们定义了JobDetail和Trigger,springboot会帮装我们自动把他们关联起来,并执行。相当于为我们创建了scheduler,并且执行了start操作,非常方便,举个例子:
具体工作:
public class AutoSubmitQuestionnaireJob implements Job, Serializable {
@Autowired
private QUserQuestionnaireMapper qUserQuestionnaireMapper;
@Autowired
private QQuestionnaireMapper qQuestionnaireMapper;
@Transactional(rollbackFor = Exception.class)
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.info("==========问卷--提交--定时任务开始=========" + LocalDateTime.now());
List<QUserQuestionnaire> qUserQuestionnaireList = qUserQuestionnaireMapper.selectList(new LambdaQueryWrapper<QUserQuestionnaire>()
.eq(QUserQuestionnaire::getUserQuestionnaireStatus, UserQuestionnaireStatus.ANSWERING.getType())
.le(QUserQuestionnaire::getEndTime, LocalDateTime.now()));
log.info("=====需要提交的问卷有:" + qUserQuestionnaireList.toString());
if (null != qUserQuestionnaireList && qUserQuestionnaireList.size() > 0) {
qUserQuestionnaireList.forEach(qUserQuestionnaire -> {
if (qUserQuestionnaireMapper.updateStatusAndScoreByUserQuestionnaireId(qUserQuestionnaire.getUserQuestionnaireId(), UserQuestionnaireStatus.SUBMITTED.getType(), LocalDateTime.now()) > 0) {
qQuestionnaireMapper.updateComplete(qUserQuestionnaire.getQuestionnaireId());
}
});
}
log.info("==========问卷--提交--定时任务结束=========" + LocalDateTime.now());
}
}
job和trigger初始化:
@Configuration
public class QuartzSchedulerConfig {
@Autowired
private DataSource dataSource;
private static final Logger Logger = LoggerFactory.getLogger(QuartzSchedulerConfig.class);
private static final String QUARTZ_PROPERTIES_NAME = "/quartz.properties";
// 使用单例创建
@Bean(name = "autoOpenQuestionnaireTrigger")
public CronTriggerFactoryBean creditScoreStatisticsTrigger(@Qualifier("autoOpenQuestionnaire") JobDetail jobDetail) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobDetail);
//0 10 0 1 * ? 每月1号的0:10:00执行 0 0 2 1 * ? * 每月的1日的凌晨2点调整任务
cronTriggerFactoryBean.setCronExpression("31 */1 * * * ?");
return cronTriggerFactoryBean;
}
// 使用单例创建
@Bean(name = "autoOpenQuestionnaire")
public JobDetailFactoryBean autoOpenQuestionnaire() {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(AutoOpenQuestionnaireJob.class);
jobDetailFactoryBean.setDurability(true);
return jobDetailFactoryBean;
}
}
结果:
2022-01-17 18:32:31 INFO quartzScheduler_Worker-1 com.cloud.crea.creasuytest.admin.job.task.AutoOpenQuestionnaireJob ==========问卷--上架--定时任务开始=========2022-01-17T18:32:31.113
2022-01-17 18:32:31 INFO quartzScheduler_Worker-1 com.cloud.crea.creasuytest.admin.job.task.AutoOpenQuestionnaireJob ==========问卷--上架--定时任务结束=========2022-01-17T18:32:31.342
持久化
修改上述configuration文件:注入连接和配置,最后加上quartz的相关数据库就ok啦
@Configuration
public class QuartzSchedulerConfig {
@Autowired
private DataSource dataSource;
private static final Logger Logger = LoggerFactory.getLogger(QuartzSchedulerConfig.class);
private static final String QUARTZ_PROPERTIES_NAME = "/quartz.properties";
@Bean
public JobFactory jobFactory(ApplicationContext applicationContext) {
AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory, CronTrigger[] cronTrigger, JobDetail[]
jobDetails) {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
try {
factoryBean.setQuartzProperties(quartzProperties());
factoryBean.setDataSource(dataSource);
factoryBean.setJobFactory(jobFactory);
factoryBean.setTriggers(cronTrigger);
factoryBean.setJobDetails(jobDetails);
factoryBean.setOverwriteExistingJobs(true);
factoryBean.setApplicationContextSchedulerContextKey("applicationContextKey");
} catch (Exception e) {
Logger.error("加载 {} 配置文件失败.", QUARTZ_PROPERTIES_NAME, e);
throw new RuntimeException("加载配置文件失败", e);
}
return factoryBean;
}
@Bean(name = "autoOpenQuestionnaireTrigger")
public CronTriggerFactoryBean creditScoreStatisticsTrigger(@Qualifier("autoOpenQuestionnaire") JobDetail jobDetail) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobDetail);
//0 10 0 1 * ? 每月1号的0:10:00执行 0 0 2 1 * ? * 每月的1日的凌晨2点调整任务
cronTriggerFactoryBean.setCronExpression("31 */1 * * * ?");
return cronTriggerFactoryBean;
}
@Bean(name = "autoOpenQuestionnaire")
public JobDetailFactoryBean autoOpenQuestionnaire() {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(AutoOpenQuestionnaireJob.class);
jobDetailFactoryBean.setDurability(true);
return jobDetailFactoryBean;
}
class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;
@Override
public void setApplicationContext(final ApplicationContext context) {
beanFactory = context.getAutowireCapableBeanFactory();
}
@Override
protected Object createJobInstance(final TriggerFiredBundle bundle)
throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
}
private Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_PROPERTIES_NAME));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
}