以下是Spring Boot整合Quartz实现定时任务数据库动态配置的步骤:
<!-- Quartz依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- 数据库连接依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
spring.datasource.url=jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
@Entity
@Data
public class QuartzConfig {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 任务名称
private String name;
// 任务分组
private String group;
// Cron表达式
private String cronExpression;
// Job描述
private String jobDescription;
}
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
// 获取JobDataMap中的参数信息
JobDataMap dataMap = context.getMergedJobDataMap();
// 不同任务 相同的 key 可以拿到不同的 value
String param1 = dataMap.getString("param1");
// 不同任务 相同的 key 可以拿到不同的 value
String param2 = dataMap.getString("param2");
// 执行具体的定时任务逻辑,使用参数信息等
System.out.println("Hello, Quartz!");
}
}
@Repository
public interface QuartzConfigRepository extends JpaRepository<QuartzConfig, Long> {
// 省略自定义查询方法
// 新增定时任务配置
QuartzConfig save(QuartzConfig quartzConfig);
}
@Configuration
public class QuartzConfig {
@Autowired
private DataSource dataSource;
// 配置SchedulerFactoryBean,用于创建调度器实例
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
// 创建 SchedulerFactoryBean 实例
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
// 设置数据源
schedulerFactoryBean.setDataSource(dataSource);
// 设置 ApplicationContext 在 SchedulerContext 中的 key 值,在 Scheduler 调度任务时,可以通过 SchedulerContext 获取当前的 ApplicationContext 对象
schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
// 设置任务执行器
schedulerFactoryBean.setTaskExecutor(schedulerThreadPool());
// 设置是否自动启动 Scheduler
schedulerFactoryBean.setAutoStartup(true);
// 设置是否覆盖已存在的 job
/*
当该属性设置为 true 时,如果 Quartz 发现已有相同名称和分组的触发器和任务存在,
则会替换掉原来的触发器和任务。如果该属性设置为 false,则不会覆盖已经存在的任务,
而是抛出一个异常。需要注意的是,如果调度器中有正在执行的任务,它们不受此属性的影响,
仍然会继续执行直到完成。
*/
schedulerFactoryBean.setOverwriteExistingJobs(true);
// 调用了方法 quartzProperties() 来获取 Properties 对象
schedulerFactoryBean.setQuartzProperties(quartzProperties());
// 返回创建好的 SchedulerFactoryBean 实例
return schedulerFactoryBean;
}
// 配置线程池,用于执行定时任务
@Bean
public TaskExecutor schedulerThreadPool() {
// 创建 ThreadPoolTaskExecutor 实例
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置线程池中线程的名称前缀为 "quartz-thread-"
executor.setThreadNamePrefix("quartz-thread-");
// 设置核心线程数为 5
executor.setCorePoolSize(5);
// 设置最大线程数为 10
executor.setMaxPoolSize(10);
// 设置队列容量为 1024
executor.setQueueCapacity(1024);
// 初始化线程池
executor.initialize();
// 返回创建好的 ThreadPoolTaskExecutor 实例。这个实例可以用来执行调度任务
return executor;
}
// 配置Quartz的属性,例如jobStore、schedulerName等
private Properties quartzProperties() {
// 创建一个 Properties 实例,用于存储 Quartz 的配置属性
Properties properties = new Properties();
// 设置调度器实例的名称
properties.setProperty("org.quartz.scheduler.instanceName", "HandsomeScheduler");
// 让 Quartz 自动生成调度器实例 ID
properties.setProperty("org.quartz.scheduler.instanceId", "AUTO");
// 指定 Quartz 使用数据库作为作业存储器,并启用事务
properties.setProperty("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
// 指定 Quartz 使用标准 JDBC 委托类来管理数据库和作业存储器
properties.setProperty("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
// 指定 Quartz 使用名为 "HandsomeDB" 的数据源
properties.setProperty("org.quartz.jobStore.dataSource", "HandsomeDB");
// 指定 Quartz 在数据库中使用的表名前缀
properties.setProperty("org.quartz.jobStore.tablePrefix", "QRTZ_");
// 设置 Quartz 集群模式为非集群模式
properties.setProperty("org.quartz.jobStore.isClustered", "false");
// 指定 "HandsomeDB" 数据源使用的 JDBC 驱动程序
properties.setProperty("org.quartz.dataSource.HandsomeDB.driver", "com.mysql.cj.jdbc.Driver");
// 指定 "HandsomeDB" 数据源使用的 JDBC URL
properties.setProperty("org.quartz.dataSource.myDS.URL", "jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai");
// 指定 "HandsomeDB" 数据源使用的用户名
properties.setProperty("org.quartz.dataSource.HandsomeDB.user", "root");
// 指定 "HandsomeDB" 数据源使用的密码
properties.setProperty("org.quartz.dataSource.HandsomeDB.password", "root");
// 指定 "HandsomeDB" 数据源允许的最大连接数
properties.setProperty("org.quartz.dataSource.HandsomeDB.maxConnections", "10");
// 为 "HandsomeDB" 数据源设置一个用于测试连接是否可用的 SQL 查询语句
properties.setProperty("org.quartz.dataSource.HandsomeDB.validationQuery", "select 1");
// 返回创建好的 Quartz 的配置属性 Properties 实例
return properties;
}
}
在以上示例代码中,我们通过@Configuration注解标记了QuartzConfig类,并在其中进行SchedulerFactoryBean的配置。具体包括:
配置数据源dataSource,用于SchedulerFactoryBean连接数据库。
创建schedulerFactoryBean Bean实例,并设置相关属性,例如调度器名称、线程池、自动启动等,最后返回schedulerFactoryBean。
创建schedulerThreadPool Bean实例,用于执行定时任务的线程池配置。
配置quartzProperties,用于定义Quartz的属性,例如jobStore、schedulerName等。
需要注意的是,在实际生产环境中,我们可能还需要根据具体业务需求,对线程池、数据源等进行进一步的优化配置。
@Service
public class QuartzConfigService {
@Autowired
private QuartzConfigRepository quartzConfigRepository;
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
// 初始化调度器,并从数据库中读取定时任务配置信息,创建对应的定时任务
@PostConstruct
public void initScheduler() throws Exception {
// 获取调度器实例
Scheduler scheduler = schedulerFactoryBean.getScheduler();
// 查询数据库中所有的定时任务配置信息
List<QuartzConfig> quartzConfigs = quartzConfigRepository.findAll();
// 遍历定时任务配置信息列表,为每个定时任务创建JobDetail和Trigger对象,并添加到调度器中
for (QuartzConfig config : quartzConfigs) {
// 创建一个JobDetail对象,用于描述Job实现类及其他一些静态信息
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity(config.getName(), config.getGroup()) // 定义任务名称和分组
.usingJobData("param1", "value1")
.build();
// 创建一个Trigger对象,用于定义周期性执行的时间规则等
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(config.getName(), config.getGroup()) // 定义任务名称和分组
.withSchedule(CronScheduleBuilder.cronSchedule(config.getCronExpression())) // 定义Cron表达式
.usingJobData("param2", "value2")
.build();
// 将JobDetail和Trigger关联到调度器中,实现任务的调度
scheduler.scheduleJob(jobDetail, trigger);
}
// 启动调度器
scheduler.start();
}
// 新增定时任务配置 不影响原来的定时任务
public void addQuartzConfig(QuartzConfig config) throws Exception {
// 保存定时任务配置信息到数据库
quartzConfigRepository.save(config);
// 获取调度器实例
Scheduler scheduler = schedulerFactoryBean.getScheduler();
// 创建一个JobDetail对象,用于描述Job实现类及其他一些静态信息
JobDetail jobDetail = JobBuilder.newJob(MyJob.class)
.withIdentity(config.getName(), config.getGroup()) // 定义任务名称和分组
.build();
// 创建一个Trigger对象,用于定义周期性执行的时间规则等
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(config.getName(), config.getGroup()) // 定义任务名称和分组
.withSchedule(CronScheduleBuilder.cronSchedule(config.getCronExpression())) // 定义Cron表达式
.build();
// 将JobDetail和Trigger关联到调度器中,实现任务的调度
scheduler.scheduleJob(jobDetail, trigger);
}
}
在以上示例代码中,我们通过@PostConstruct注解标记的initScheduler()方法,在Spring容器初始化完成后自动执行,实现从数据库中读取定时任务配置信息,并创建对应的JobDetail和Trigger对象,添加到调度器中,最后启动调度器,实现自动运行定时任务的功能。addQuartzConfig方法实现新增定时任务配置。
需要注意的是,在实际生产环境中,我们可能还需要根据具体业务需求,对定时任务的配置信息进行更新、删除等操作,因此需要在QuartzConfigService中添加相应的方法来实现这些功能。