Springboot整合Quartz定时任务框架(Spring解决方案)
spring提供的quartz解决发难
目录
前言
系统现在有定时任务触发业务场景的需求,并且频率及次数不固定,即可以动态定义任务的频率及次数,因项目本身还是基于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
@Bean
public DataSource quartzDataSource(DataSourceProperties schedulerProperties) {
return schedulerProperties.initializeDataSourceBuilder().build();
}
@Bean
public PlatformTransactionManager transactionManager(@Qualifier("quartzDataSource") DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
配置文件:
spring:
scheduler:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://***/quartz
username: root
password: ****
type: com.mysql.cj.jdbc.MysqlDataSource
quartz:
job-store-type: jdbc
jdbc:
initialize-schema: always
comment-prefix: #
properties:
org:
quartz:
jobStore:
class: org.springframework.scheduling.quartz.LocalDataSourceJobStore
driverDelegateClass: 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.SimpleThreadPool
threadCount: 4
threadPriority: 5
threadsInheritContextClassLoaderOfInitializingThread: true
2、配置JOB实例与触发器
JobDetailFactoryBean 是spring退出的quartz解决方案,用来产生job。
SpringBoot触发器分类分别为
SimpleTriggerFactoryBean:简单触发器,通过配置间隔时间实现
CronTriggerFactoryBean: cron触发器,key通过配置cron表达式来实现
@Configuration
public class JobConfig {
@Bean
JobDetailFactoryBean dailyJob() {
JobDetailFactoryBean bean = new JobDetailFactoryBean();
bean.setJobClass(DailyJobExecutor.class);
bean.setDurability(true);
return bean;
}
@Bean
CronTriggerFactoryBean dailyTrigger(@Qualifier("dailyJob") JobDetail jobDetail) {
CronTriggerFactoryBean bean = new CronTriggerFactoryBean();
bean.setJobDetail(jobDetail);
//cron 每日一次
bean.setCronExpression("0 0 0 * * ?");
return bean;
}
@Bean
SimpleTriggerFactoryBean 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 {
@Resource
private AutowireCapableBeanFactory capableBeanFactory;
@NotNull
@Override
protected 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.Resource
private List<CronTriggerFactoryBean> cronTriggerFactoryBeans;
@Bean
public 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 {
@Resource
private List<DailyJobService> dailyJobServiceList;
@Override
protected 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 {
@Override
public void execute() {
log.info("OralTackJobServiceImpl start....");
//业务逻辑
}
}
}
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)