Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的程序
(1)通过start.spring.io快速构建spring boot工程,加上quartz依赖
(2)入门程序编写
public class QuartzTest { public static void main(String[] args) { try { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); // define the job and tie it to our HelloJob class // 定义一个需要去执行的job JobDetail job = newJob(HelloJob.class) .withIdentity("job1", "group1") .build(); /** * 四种触发器: * * CalendarIntervalTriggerImpl (org.quartz.impl.triggers) * SimpleTriggerImpl (org.quartz.impl.triggers) * DailyTimeIntervalTriggerImpl (org.quartz.impl.triggers) * CronTriggerImpl (org.quartz.impl.triggers) */ // 创建一个触发器,每隔5秒钟触发执行这个job Trigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(simpleSchedule() // 简单调度 .withIntervalInSeconds(5) // 每隔5秒执行一次 .repeatForever()) // 永远执行 .build(); // 执行这个job scheduler.scheduleJob(job, trigger); TimeUnit.SECONDS.sleep(20); scheduler.shutdown(); }catch (Exception e){ e.printStackTrace(); } } } public class HelloJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { System.out.println("hello,quartz " + DateUtil.format(new Date()) + ",当前线程:" + Thread.currentThread().getName()); } } 运行结果: hello,quartz 2021-12-25 10:39:11,当前线程:DefaultQuartzScheduler_Worker-1 hello,quartz 2021-12-25 10:39:16,当前线程:DefaultQuartzScheduler_Worker-2 hello,quartz 2021-12-25 10:39:21,当前线程:DefaultQuartzScheduler_Worker-3 hello,quartz 2021-12-25 10:39:26,当前线程:DefaultQuartzScheduler_Worker-4 hello,quartz 2021-12-25 10:39:31,当前线程:WorkerThread-LastJob
public class _01_QuartzTest { public static void main(String[] args) { try { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); // 定义一个需要去执行的job JobDetail job = newJob(_01_HelloJob.class) .withIdentity("job1", "group1") .build(); // 创建一个触发器,每隔1秒钟触发执行这个job Trigger trigger1 = newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(simpleSchedule() // 简单调度 .withIntervalInSeconds(1) // 每隔1秒执行一次 .repeatForever()) // 永远执行 .build(); // 创建第二个触发器,每隔1秒钟触发执行这个job Trigger trigger2 = newTrigger() .withIdentity("trigger2", "group1") .forJob("job1","group1") // 第二个触发器 通过jobName和jobGroup名称确定唯一的job .startNow() .withSchedule(simpleSchedule() // 简单调度 .withIntervalInSeconds(1) // 每隔1秒执行一次 .repeatForever()) // 永远执行 .build(); // 执行这个job scheduler.scheduleJob(job, trigger1); scheduler.scheduleJob(trigger2); // trigger2已经指定了job TimeUnit.SECONDS.sleep(3); scheduler.shutdown(); }catch (Exception e){ e.printStackTrace(); } } } public class _01_HelloJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { StringJoiner std = new StringJoiner(" ") .add("hello,quartz") .add(DateUtil.format(new Date())) // 执行时候的时间 .add(Thread.currentThread().getName()) // 当前线程的名称 .add(jobExecutionContext.getTrigger().getKey().getName()); // 获取trigger名称TriggerKey(String name, String group) System.out.println(std); } } 结果; hello,quartz 2021-12-25 11:10:11 DefaultQuartzScheduler_Worker-1 trigger1 hello,quartz 2021-12-25 11:10:11 DefaultQuartzScheduler_Worker-2 trigger2 hello,quartz 2021-12-25 11:10:12 DefaultQuartzScheduler_Worker-3 trigger1 hello,quartz 2021-12-25 11:10:12 DefaultQuartzScheduler_Worker-4 trigger2 hello,quartz 2021-12-25 11:10:13 DefaultQuartzScheduler_Worker-5 trigger1 hello,quartz 2021-12-25 11:10:13 DefaultQuartzScheduler_Worker-6 trigger2 hello,quartz 2021-12-25 11:10:14 WorkerThread-LastJob trigger1
quartz模型
public class _02_QuartzTest { public static void main(String[] args) { try { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); // 定义一个需要去执行的job JobDetail job1 = newJob(_02_HelloJob.class) // 同一个job .withIdentity("job1", "group1") .build(); // 定义一个需要去执行的job JobDetail job2 = newJob(_02_HelloJob.class) // 同一个job .withIdentity("job2", "group1") .build(); // 创建一个触发器,每隔1秒钟触发执行这个job Trigger trigger1 = newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(simpleSchedule() // 简单调度 .withIntervalInSeconds(1) // 每隔1秒执行一次 .repeatForever()) // 永远执行 .build(); // 创建一个触发器,每隔1秒钟触发执行这个job Trigger trigger2 = newTrigger() .withIdentity("trigger2", "group1") .startNow() .withSchedule(simpleSchedule() // 简单调度 .withIntervalInSeconds(1) // 每隔1秒执行一次 .repeatForever()) // 永远执行 .build(); // 执行这个job scheduler.scheduleJob(job1, trigger1); scheduler.scheduleJob(job2,trigger2); TimeUnit.SECONDS.sleep(3); scheduler.shutdown(); }catch (Exception e){ e.printStackTrace(); } } } public class _02_HelloJob implements Job { @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { StringJoiner std = new StringJoiner(" ") .add("hello,quartz") .add(DateUtil.format(new Date())) // 执行时候的时间 .add(Thread.currentThread().getName()) // 当前线程的名称 .add(jobExecutionContext.getTrigger().getKey().getName()) // 获取trigger名称 .add(jobExecutionContext.getJobDetail().getKey().getName()); // 获取JobDetail名称 System.out.println(std); } } 结果: hello,quartz 2021-12-25 11:28:05 DefaultQuartzScheduler_Worker-1 trigger1 job1 hello,quartz 2021-12-25 11:28:05 DefaultQuartzScheduler_Worker-2 trigger2 job2 hello,quartz 2021-12-25 11:28:06 DefaultQuartzScheduler_Worker-3 trigger1 job1 hello,quartz 2021-12-25 11:28:06 DefaultQuartzScheduler_Worker-4 trigger2 job2 hello,quartz 2021-12-25 11:28:07 DefaultQuartzScheduler_Worker-5 trigger1 job1 hello,quartz 2021-12-25 11:28:07 DefaultQuartzScheduler_Worker-6 trigger2 job2 hello,quartz 2021-12-25 11:28:08 DefaultQuartzScheduler_Worker-7 trigger1 job1 hello,quartz 2021-12-25 11:28:08 DefaultQuartzScheduler_Worker-8 trigger2 job2
group是用来标记、方便管理的
name是用来标记的
举例:
一个物流系统有三个模块: 运输工具模块 运输人员模块 物流信息模块 job是每天凌晨结算前一天的物流信息 Trigger{group:物流信息,name:日结-auto} JobDetail{group:物流信息,name:日结} 由于一些原因,需要修改昨天的物流信息,一般会在后台提供手动触发的功能 Trigger{group:物流信息,name:日结-manual}
(1)可以指定触发的时间间隔
(2)可以指定触发的次数
核心方法
CronScheduleBuilder.cronSchedule("* * * * * ? *") // 传入cron表达式
解释:
(6)传入变量
// 定义一个需要去执行的job JobDetail job = newJob(_05_HelloJob.class) .withIdentity("job1", "group1") .usingJobData("JobDetail_key","JobDetail_value") .build(); // 创建一个触发器,每隔1秒钟触发执行这个job Trigger trigger = newTrigger() .withIdentity("trigger", "group1") .usingJobData("trigger_key","trigger_value") .startNow() .withSchedule( CronScheduleBuilder.cronSchedule("* * * * * ? *") // 传入cron表达式 ) .build();
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //获取传入的变量 Trigger trigger = jobExecutionContext.getTrigger(); JobDetail jobDetail = jobExecutionContext.getJobDetail(); JobDataMap triggerJobDataMap = trigger.getJobDataMap(); System.out.println("triggerJobDataMap ==> " + triggerJobDataMap.get("trigger_key")); //获取传入的变量 JobDataMap jobDetailJobDataMap = jobDetail.getJobDataMap(); System.out.println("jobDetailJobDataMap ==> " + jobDetailJobDataMap.get("JobDetail_key")); StringJoiner std = new StringJoiner(" ") .add("hello,quartz") .add(DateUtil.format(new Date())) // 执行时候的时间 .add(Thread.currentThread().getName()) // 当前线程的名称 .add(jobExecutionContext.getTrigger().getKey().getName()) // 获取trigger名称 .add(jobExecutionContext.getJobDetail().getKey().getName()); // 获取JobDetail名称 System.out.println(std); }
定义一个job
public class _01_SpringJob extends QuartzJobBean { //继承QuartzJobBean @Autowired private SpringAutoService springAutoService;// 注入 @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { StringJoiner std = new StringJoiner("---") .add("hello,quartz") .add(DateUtil.format(new Date())) // 执行时候的时间 .add(Thread.currentThread().getName()); System.out.println(std); System.out.println(springAutoService.getHelloSpring()); } } @Service public class SpringAutoService { public String getHelloSpring(){ return "hello spring"; } }
@Component public class JobInit { @Autowired public Scheduler scheduler; // 自动注入 @PostConstruct public void initJob() throws Exception{ JobDetail jobDetail = JobBuilder.newJob(_01_SpringJob.class) .withIdentity("job1", "group1") .build(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(simpleSchedule() // 简单调度 .withIntervalInSeconds(1) // 每隔1秒执行一次 .withRepeatCount(3) ).build(); scheduler.scheduleJob(jobDetail,trigger); } } 启动springboot工程: *****************QuartzStudyApplication启动成功************************ hello,quartz---2021-12-25 17:35:30---quartzScheduler_Worker-2 hello spring hello,quartz---2021-12-25 17:35:31---quartzScheduler_Worker-3 hello spring hello,quartz---2021-12-25 17:35:32---quartzScheduler_Worker-4 hello spring
@Configuration public class JobConfig { @Bean public JobDetail getJobDetail(){ JobDetail jobDetail = JobBuilder.newJob(_01_SpringJob.class) .withIdentity("job1", "group1") .storeDurably() .build(); return jobDetail; } @Bean public Trigger getTrigger(){ Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("trigger1", "group1") .forJob("job1","group1") .startNow() .withSchedule(simpleSchedule() // 简单调度 .withIntervalInSeconds(1) // 每隔1秒执行一次 .withRepeatCount(3) ).build(); return trigger; } } *****************QuartzStudyApplication启动成功************************ hello,quartz---2021-12-25 17:48:46---quartzScheduler_Worker-1 hello spring hello,quartz---2021-12-25 17:48:47---quartzScheduler_Worker-2 hello spring hello,quartz---2021-12-25 17:48:48---quartzScheduler_Worker-3 hello spring hello,quartz---2021-12-25 17:48:49---quartzScheduler_Worker-4 hello spring
配置如下:
(1) quartz的表和业务库在一起
# 配置数据源 spring: datasource: username: root password: 123456 url: jdbc:mysql://127.0.0.1:3306/exercise?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useUnicode=true&useSSL=false&serverTimezone=Asia/Shanghai driver-class-name: com.mysql.cj.jdbc.Driver # quartz持久化 会在exercise中创建quartz表 quartz: job-store-type: jdbc jdbc: initialize-schema: always // 每次启动会重新创建表 初次启动后可以改为never
(2) quartz的表单独在一个库中
@Bean @QuartzDataSource public DataSource dataSource(){ DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(""); dataSource.setUsername(""); dataSource.setPassword(""); dataSource.setUrl(""); return dataSource; }
quartz: properties: # 添加原生配置 org.quartz.threadPool.threadCount: 10 username: root ...
5、集群环境
(1)只让集群中的一台服务器去跑定时任务(会浪费其他服务器的性能)
(2)每台服务器都会执行定时任务,但是一个任务只会分配到一台机器上