Springboot整合Quartz定时任务框架(Spring解决方案)
目录
前言
介绍
集成
POM依赖
基础配置
1、配置数据源
3、配置SchedulerJobFactory
4、配置SchedulerFactoryBean
业务集成
job编写
接口编写
接口实现
前言
系统现在有定时任务触发业务场景的需求,并且频率及次数不固定,即可以动态定义任务的频率及次数,因项目本身还是基于springboot开发,暂定还是使用Quartz,后期再升级,单独的Quartz配置有些问题,主要介绍springboot提供的集成方式。
介绍
多的不多,说一下quartz的表结构
- QRTZ_BLOG_TRIGGERS Trigger 作为 Blob 类型存储
- QRTZ_CALENDARS 以 Blob 类型存储 Quartz 的 Calendar 信息
- QRTZ_CRON_TRIGGERS 存储 Cron Trigger,包括 Cron 表达式和时区信息
- QRTZ_FIRED_TRIGGERS 存储与已触发的 Trigger 相关的状态信息
- QRTZ_PAUSED_TRIGGER_GRPS 存储已暂停的 Trigger 组的信息
- QRTZ_SCHEDULER_STATE 存储少量的有关 Scheduler 的状态信息,和别的 Scheduler 实例
- QRTZ_SIMPLE_TRIGGERS 存储简单的 Trigger,包括重复次数,间隔,以及已触的次数
- QRTZ_TRIGGERS 存储已配置的 Trigger 的信息
- QRTZ_LOCKS 存储程序的非观锁的信息(假如使用了悲观锁)
- QRTZ_JOB_DETAILS 存储每一个已配置的 Job 的详细信息
集成
废话不多说,直接开搞
POM依赖
使用springboot-starter的依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId><version>2.7.9</version>
</dependency>
配置文件
基础配置
如果不想让业务的库客quartz的库在一起,可以这么做
1、配置数据源
@QuartzDataSource可以标记为quartz的库,配置数据源和事务管理器
@Configuration
public class SchedulerDataSourceConfig {private static final String QUARTZ_DATASOURCE = "spring.scheduler.datasource";@Bean@ConfigurationProperties(QUARTZ_DATASOURCE)public DataSourceProperties schedulerProperties() {return new DataSourceProperties();}@QuartzDataSource@Beanpublic DataSource quartzDataSource(DataSourceProperties schedulerProperties) {return schedulerProperties.initializeDataSourceBuilder().build();}@Beanpublic PlatformTransactionManager transactionManager(@Qualifier("quartzDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}
}
配置文件:
spring:scheduler:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://***/quartzusername: rootpassword: ****type: com.mysql.cj.jdbc.MysqlDataSourcequartz:job-store-type: jdbcjdbc:initialize-schema: alwayscomment-prefix: #properties:org:quartz:jobStore:class: org.springframework.scheduling.quartz.LocalDataSourceJobStoredriverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #我们仅为数据库制作了特定于数据库的代理useProperties: false #以指示JDBCJobStore将JobDataMaps中的所有值都作为字符串,因此可以作为名称 - 值对存储而不是在BLOB列中以其序列化形式存储更多复杂的对象。从长远来看,这是更安全的,因为您避免了将非String类序列化为BLOB的类版本问题。tablePrefix: scheduler_ #数据库表前缀misfireThreshold: 60000 #在被认为“失火”之前,调度程序将“容忍”一个Triggers将其下一个启动时间通过的毫秒数。默认值(如果您在配置中未输入此属性)为60000(60秒)。clusterCheckinInterval: 5000 #设置此实例“检入”*与群集的其他实例的频率(以毫秒为单位)。影响检测失败实例的速度。isClustered: true #打开群集功能threadPool: #连接池class: org.quartz.simpl.SimpleThreadPoolthreadCount: 4threadPriority: 5threadsInheritContextClassLoaderOfInitializingThread: true
2、配置JOB实例与触发器
JobDetailFactoryBean 是spring退出的quartz解决方案,用来产生job。
SpringBoot触发器分类分别为
SimpleTriggerFactoryBean:简单触发器,通过配置间隔时间实现
CronTriggerFactoryBean: cron触发器,key通过配置cron表达式来实现
@Configuration
public class JobConfig {@BeanJobDetailFactoryBean dailyJob() {JobDetailFactoryBean bean = new JobDetailFactoryBean();bean.setJobClass(DailyJobExecutor.class);bean.setDurability(true);return bean;}@BeanCronTriggerFactoryBean dailyTrigger(@Qualifier("dailyJob") JobDetail jobDetail) {CronTriggerFactoryBean bean = new CronTriggerFactoryBean();bean.setJobDetail(jobDetail);//cron 每日一次bean.setCronExpression("0 0 0 * * ?");return bean;}@BeanSimpleTriggerFactoryBean simpleTrigger(@Qualifier("dailyJob") JobDetail jobDetail) {SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();bean.setJobDetail(jobDetail);//多少秒一次bean.setRepeatInterval(5000L);bean.setStartDelay(5000L);return bean;}
}
3、配置SchedulerJobFactory
因为我们最终写的job对象最终是new出来quartz管理的,如果在里面使用 @Autowired等spring的注解不会生效,所以配置spring工厂,把实例交给spring管理
@Component
public class SchedulerJobFactory extends SpringBeanJobFactory {@Resourceprivate AutowireCapableBeanFactory capableBeanFactory;@NotNull@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Object jobInstance = super.createJobInstance(bundle);// 进行注入(Spring管理该Bean)capableBeanFactory.autowireBean(jobInstance);return jobInstance;}
}
4、配置SchedulerFactoryBean
定时工厂,将我们配置的触发器、数据源、job工厂都注入进来
@Configuration
public class SchedulerConfig {@javax.annotation.Resourceprivate List<CronTriggerFactoryBean> cronTriggerFactoryBeans;@Beanpublic SchedulerFactoryBean schedulerFactoryBean (@Qualifier("quartzDataSource") DataSource dataSource,@Qualifier("schedulerJobFactory") JobFactory jobFactory,@Qualifier("quartzTransactionManager")PlatformTransactionManager transactionManager) throws Exception {SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();schedulerFactoryBean.setBeanName("order-scheduler");schedulerFactoryBean.setDataSource(dataSource);Resource resource = new PathMatchingResourcePatternResolver().getResources("classpath*:/application-scheduler.yml")[0];schedulerFactoryBean.afterPropertiesSet();schedulerFactoryBean.setConfigLocation(resource);schedulerFactoryBean.setJobFactory(jobFactory);schedulerFactoryBean.setTransactionManager(transactionManager);schedulerFactoryBean.setTriggers();CronTrigger[] triggers = cronTriggerFactoryBeans.stream().map(CronTriggerFactoryBean::getObject).toArray(CronTrigger[]::new);schedulerFactoryBean.setTriggers(triggers);return schedulerFactoryBean;}
}
业务集成
job编写
上面JobConfig里面配置的job执行类,因为我用的触发器为cron触发,频率为每天一次,因此为了解耦,每个需要每天执行的job都可以使用这个,注入了接口 DailyJobService, 有多个实现
@Slf4j
@DisallowConcurrentExecution
@PersistJobDataAfterExecution
@Component
public class DailyJobExecutor extends QuartzJobBean {@Resourceprivate List<DailyJobService> dailyJobServiceList;@Overrideprotected void executeInternal(JobExecutionContext context) {log.info("dailyJobService start...");dailyJobServiceList.forEach(DailyJobService::execute);}
}
接口编写
DailyJobService,里面定义了执行方法
@Service
public interface DailyJobService {void execute();
}
接口实现
里面写具体的业务逻辑
@Slf4j
@Service
public class OralTackJobServiceImpl implements DailyJobService {@Overridepublic void execute() {log.info("OralTackJobServiceImpl start....");//业务逻辑}}
}