1.添加pom文件
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>5.3.24</version> <!-- 根据你的 Spring 版本调整 -->
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
2.配置文件
server:
port: 80
spring:
application:
name: quartz_demo
servlet:
multipart:
enabled: true
max-file-size: 200MB
max-request-size: 200MB
datasource:
type: com.alibaba.druid.pool.DruidDataSource
dynamic:
primary: master
strict: false
datasource:
master:
url: jdbc:mysql://192.168.1.42:3306/base?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Qazxsw21`
driver-class-name: com.mysql.cj.jdbc.Driver
quartz:
url: jdbc:mysql://192.168.1.43:3306/quartz?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
username: root
password: Qazxsw21`
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
initial-size: 8
min-idle: 1
max-active: 20
max-wait: 60000
time-between-eviction-runsMillis: 60000
min-evictable-idle-timeMillis: 30000
validation-query: select 1
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-open-prepared-statements: 20
max-pool-prepared-statement-per-connection-size: 20
filters: stat
connection-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
use-global-data-source-stat: true
mvc:
pathmatch:
matching-strategy: ant_path_matcher
org:
quartz:
scheduler:
# 调度器实例名称,用于标识特定的调度器实例
instanceName: SERVICEX-SCHEDULER-INSTANCE
# 实例ID,AUTO表示自动生成
instanceId: AUTO
instanceIdGenerator:
# 实例ID生成器类,使用简单的自增ID生成器
class: org.quartz.simpl.SimpleInstanceIdGenerator
jobStore:
# 作业存储方式,使用JDBC事务型存储
class: org.quartz.impl.jdbcjobstore.JobStoreTX
# JDBC驱动委托类,标准JDBC实现
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 数据库表前缀
tablePrefix: QRTZ_
# 是否启用集群模式
isClustered: true
# 集群节点检查间隔(毫秒)
clusterCheckinInterval: 15000
# 是否将JobDataMap中的值作为字符串存储
useProperties: false
# 数据库行锁SQL(针对不同数据库可能需要调整)
selectWithLockSQL: SELECT * FROM {0}LOCKS WHERE LOCK_NAME = ? FOR UPDATE
threadPool:
# 线程池实现类
class: org.quartz.simpl.SimpleThreadPool
# 线程池大小
threadCount: 10
# 线程优先级(1-10)
threadPriority: 5
# 线程是否继承初始化线程的上下文类加载器
threadsInheritContextClassLoaderOfInitializingThread: true
3.quartz的config文件(这里可以添加动态增删改查任务的方法,具体大家自己找一下,网上很多)
package com.quartz.demo.bootquartz.scheduler;
import com.baomidou.dynamic.datasource.DynamicRoutingDataSource;
import org.quartz.Scheduler;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
import java.util.Properties;
/**
* @ClassName SchedulerConfig
* @Description 任务调度器
* @Author LiuJiWei
* @Date 2025/3/26 星期三
* @Version 1.0
*/
@Component
@Configuration
public class SchedulerConfig {
/**
* 调度器
*/
private Scheduler scheduler;
/**
* 获取调度器
*
* @return Scheduler
* @throws Exception
*/
@Bean
public Scheduler scheduler(SchedulerFactoryBean schedulerFactoryBean) {
scheduler = schedulerFactoryBean.getScheduler();
return scheduler;
}
/**
* 读取Quartz的配置文件配置
* 给 schedulerFactory 方法用
*
* @return Properties
* @throws Exception
*/
@Bean
public Properties quartzProperties() throws Exception {
PropertiesFactoryBean factory = new PropertiesFactoryBean();
factory.setLocation(new ClassPathResource("/application.yml"));
factory.afterPropertiesSet();
return factory.getObject();
}
/**
* 配置调度器参数
*
* @return SchedulerFactoryBean
* @throws Exception
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DynamicRoutingDataSource dataSource) throws Exception {
// 创建调度器工厂Bean
SchedulerFactoryBean factory = new SchedulerFactoryBean();
// 【重要】设置调度器实例名称(集群环境中用于标识)
factory.setSchedulerName("Cluster_Quartz_Scheduler");
// 【关键】设置Quartz使用的数据源(需与quartz.properties中配置一致)
// 注意:这里从动态数据源中获取名为"quartz"的特定数据源
factory.setDataSource(dataSource.getDataSource("quartz"));
// 设置Spring应用上下文在Job中的key
// 这样在Job实现类中可以通过此key获取Spring上下文
factory.setApplicationContextSchedulerContextKey("applicationContext");
// 加载Quartz配置属性(从application.yml中读取)
factory.setQuartzProperties(quartzProperties());
// 【线程池配置】设置自定义线程池
// 注意:如果同时配置了quartz.properties中的线程池,可能会有冲突
factory.setTaskExecutor(null);
// 【启动控制】是否自动启动调度器(默认true)
// 设为false时需要手动调用start()方法
factory.setAutoStartup(true);
// 【关键】应用关闭时是否等待任务完成
// true:优雅停机,会等待正在执行的任务完成
// false:立即停止,可能中断正在执行的任务
factory.setWaitForJobsToCompleteOnShutdown(true);
// 【重要】是否覆盖已存在的Job定义
// true:启动时覆盖同名的Job/Trigger定义
// false:发现同名Job时会抛出异常
factory.setOverwriteExistingJobs(true);
// 【建议】添加以下额外配置(根据需求):
// factory.setStartupDelay(10); // 延迟N秒启动(给应用留出初始化时间)
// factory.setExposeSchedulerInRepository(true); // 集群环境下需要暴露
return factory;
}
}
测试添加任务及启动触发
1.任务
package com.quartz.demo.bootquartz.job;
import org.quartz.*;
import java.util.Date;
/**
* @ClassName QuartzJob
* @Description 任务1
* @Author LiuJiWei
* @Date 2025/3/26 星期三
* @Version 1.0
*/
@PersistJobDataAfterExecution // 持久化jobMapData
@DisallowConcurrentExecution // 禁止任务并发执行
public class QuartzJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
System.out.println("======================Quartz Job executed=============================");
System.out.println(context.getScheduler().getSchedulerInstanceId());
System.out.println("任务名称:" + context.getJobDetail().getKey().getName());
System.out.println("执行时间:" + new Date());
System.out.println("======================Quartz Job end=============================");
} catch (Exception e) {
e.printStackTrace();
}
}
}
2.项目启动则触发
package com.quartz.demo.bootquartz.trigger;
import com.quartz.demo.bootquartz.job.QuartzJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
/**
* @ClassName BootTrigger
* @Description 任务启动器
* @Author LiuJiWei
* @Date 2025/3/26 星期三
* @Version 1.0
*/
@Component
public class BootTrigger implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private Scheduler scheduler;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// 定义触发器
TriggerKey triggerKey = TriggerKey.triggerKey("bootTriggerKey", "bootTriggerGroup");
try {
// 调度器中获取触发器,如果没有则新建一个触发器
Trigger trigger = scheduler.getTrigger(triggerKey);
if (trigger == null) {
trigger = TriggerBuilder.newTrigger()
.withIdentity(triggerKey)
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?"))
.build();
// 定义要执行的任务
JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class)
.withIdentity("QuartzJobKey", "QuartzJobGroup")
.build();
// 传入调度器并开始执行任务
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
} catch (SchedulerException e) {
throw new RuntimeException(e);
}
}
}
3.启动项目
2025-03-27 08:57:02.490 INFO 10536 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 10086 (http) with context path ''
2025-03-27 08:57:02.491 INFO 10536 --- [ main] o.s.s.quartz.SchedulerFactoryBean : Starting Quartz Scheduler now
2025-03-27 08:57:02.515 INFO 10536 --- [ main] o.s.s.quartz.LocalDataSourceJobStore : Freed 0 triggers from 'acquired' / 'blocked' state.
2025-03-27 08:57:02.520 INFO 10536 --- [ main] o.s.s.quartz.LocalDataSourceJobStore : Handling 1 trigger(s) that missed their scheduled fire-time.
2025-03-27 08:57:02.548 INFO 10536 --- [ main] o.s.s.quartz.LocalDataSourceJobStore : Recovering 0 jobs that were in-progress at the time of the last shut-down.
2025-03-27 08:57:02.548 INFO 10536 --- [ main] o.s.s.quartz.LocalDataSourceJobStore : Recovery complete.
2025-03-27 08:57:02.550 INFO 10536 --- [ main] o.s.s.quartz.LocalDataSourceJobStore : Removed 0 'complete' triggers.
2025-03-27 08:57:02.551 INFO 10536 --- [ main] o.s.s.quartz.LocalDataSourceJobStore : Removed 0 stale fired job entries.
2025-03-27 08:57:02.555 INFO 10536 --- [ main] org.quartz.core.QuartzScheduler : Scheduler Cluster_Quartz_Scheduler_$_NON_CLUSTERED started.
2025-03-27 08:57:02.568 INFO 10536 --- [ main] com.quartz.demo.QuartzDemoApplication : Started QuartzDemoApplication in 2.839 seconds (JVM running for 3.393)
======================Quartz Job executed=============================
NON_CLUSTERED
任务名称:QuartzJobKey
执行时间:Thu Mar 27 08:57:02 CST 2025
======================Quartz Job end=============================
======================Quartz Job executed=============================
NON_CLUSTERED
任务名称:QuartzJobKey
执行时间:Thu Mar 27 08:57:05 CST 2025
======================Quartz Job end=============================
======================Quartz Job executed=============================
NON_CLUSTERED
任务名称:QuartzJobKey
执行时间:Thu Mar 27 08:57:10 CST 2025
======================Quartz Job end=============================