本文側重SpringBoot與Quartz的整合,Quartz的基本入門概念不清楚的小夥伴能夠看看這篇文章:任務調度框架Quartz快速入門!html
學習完非Spring環境下Quartz的使用,再來看SpringBoot你會感到更加自如,由於SpringBoot無非是利用它自動配置的特性,將一些重要的Bean自動配置到環境中,咱們直接開箱即用,關於Quartz的自動配置定義在QuartzAutoConfiguration中。java
主要是spring-boot-starter-quartz
這個依賴,是SpringBoot與Quartz的整合。mysql
<!-- 實現對 Spring MVC 的自動化配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 實現對 Quartz 的自動化配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
爲了演示兩種Trigger及兩種配置方式,咱們建立兩個不一樣的Job。git
@Slf4j public class FirstJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { String now = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()); log.info("當前的時間: " + now); } } @Slf4j public class SecondJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { String now = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(LocalDateTime.now()); log.info("SecondJob執行, 當前的時間: " + now); } }
咱們在建立Job的時候,能夠實現Job接口,也能夠繼承QuartzJobBean。web
QuartzJobBean實現了Job,而且定義了公用的execute方法,子類能夠繼承QuartzJobBean並實現executeInternal方法。spring
public abstract class QuartzJobBean implements Job { /** * This implementation applies the passed-in job data map as bean property * values, and delegates to {@code executeInternal} afterwards. * @see #executeInternal */ @Override public final void execute(JobExecutionContext context) throws JobExecutionException { try { // 將當前對象包裝爲BeanWrapper BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this); // 設置屬性 MutablePropertyValues pvs = new MutablePropertyValues(); pvs.addPropertyValues(context.getScheduler().getContext()); pvs.addPropertyValues(context.getMergedJobDataMap()); bw.setPropertyValues(pvs, true); } catch (SchedulerException ex) { throw new JobExecutionException(ex); } // 子類實現該方法 executeInternal(context); } /** * Execute the actual job. The job data map will already have been * applied as bean property values by execute. The contract is * exactly the same as for the standard Quartz execute method. * @see #execute */ protected abstract void executeInternal(JobExecutionContext context) throws JobExecutionException; }
Scheduler綁定有兩種方式,一種是使用bena的自動配置,一種是Scheduler手動配置。sql
@Configuration public class QuartzConfig { private static final String ID = "SUMMERDAY"; @Bean public JobDetail jobDetail1() { return JobBuilder.newJob(FirstJob.class) .withIdentity(ID + " 01") .storeDurably() .build(); } @Bean public Trigger trigger1() { // 簡單的調度計劃的構造器 SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(5) // 頻率 .repeatForever(); // 次數 return TriggerBuilder.newTrigger() .forJob(jobDetail1()) .withIdentity(ID + " 01Trigger") .withSchedule(scheduleBuilder) .build(); } }
@Component public class JobInit implements ApplicationRunner { private static final String ID = "SUMMERDAY"; @Autowired private Scheduler scheduler; @Override public void run(ApplicationArguments args) throws Exception { JobDetail jobDetail = JobBuilder.newJob(FirstJob.class) .withIdentity(ID + " 01") .storeDurably() .build(); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ? *"); // 建立任務觸發器 Trigger trigger = TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity(ID + " 01Trigger") .withSchedule(scheduleBuilder) .startNow() //當即執行一次任務 .build(); // 手動將觸發器與任務綁定到調度器內 scheduler.scheduleJob(jobDetail, trigger); } }
spring: # Quartz 的配置,對應 QuartzProperties 配置類 quartz: job-store-type: memory # Job 存儲器類型。默認爲 memory 表示內存,可選 jdbc 使用數據庫。 auto-startup: true # Quartz 是否自動啓動 startup-delay: 0 # 延遲 N 秒啓動 wait-for-jobs-to-complete-on-shutdown: true # 應用關閉時,是否等待定時任務執行完成。默認爲 false ,建議設置爲 true overwrite-existing-jobs: false # 是否覆蓋已有 Job 的配置 properties: # 添加 Quartz Scheduler 附加屬性 org: quartz: threadPool: threadCount: 25 # 線程池大小。默認爲 10 。 threadPriority: 5 # 線程優先級 class: org.quartz.simpl.SimpleThreadPool # 線程池類型 # jdbc: # 這裏暫時不說明,使用 JDBC 的 JobStore 的時候,才須要配置
SpringBoot自動配置中:spring.quartz
對應的配置項定義在QuartzProperties
中。數據庫
@SpringBootApplication public class DemoSpringBootApplication { public static void main(String[] args) { SpringApplication.run(DemoSpringBootApplication.class, args); } }
啓動程序,FirstJob每5s執行一次,SecondJob每10s執行一次。springboot
[eduler_Worker-1] com.hyhwky.standalone.FirstJob : FirstJob執行, 當前的時間: 2020-12-26 16:54:00 [eduler_Worker-2] com.hyhwky.standalone.SecondJob : SecondJob執行, 當前的時間: 2020-12-26 16:54:00 [eduler_Worker-3] com.hyhwky.standalone.FirstJob : FirstJob執行, 當前的時間: 2020-12-26 16:54:05 [eduler_Worker-4] com.hyhwky.standalone.SecondJob : SecondJob執行, 當前的時間: 2020-12-26 16:54:10 [eduler_Worker-5] com.hyhwky.standalone.FirstJob : FirstJob執行, 當前的時間: 2020-12-26 16:54:10 [eduler_Worker-6] com.hyhwky.standalone.FirstJob : FirstJob執行, 當前的時間: 2020-12-26 16:54:15 [eduler_Worker-7] com.hyhwky.standalone.SecondJob : SecondJob執行, 當前的時間: 2020-12-26 16:54:20
Quartz持久化配置提供了兩種存儲器:服務器
類型 | 優勢 | 缺點 |
---|---|---|
RAMJobStore | 不要外部數據庫,配置容易,運行速度快 | 由於調度程序信息是存儲在被分配給 JVM 的內存裏面,因此,當應用程序中止運行時,全部調度信息將被丟失。另外由於存儲到JVM內存裏面,因此能夠存儲多少個 Job 和 Trigger 將會受到限制 |
JDBC 做業存儲 | 支持集羣,由於全部的任務信息都會保存到數據庫中,能夠控制事物,還有就是若是應用服務器關閉或者重啓,任務信息都不會丟失,而且能夠恢復因服務器關閉或者重啓而致使執行失敗的任務 | 運行速度的快慢取決與鏈接數據庫的快慢 |
爲了測試Quartz的持久化配置,咱們事先在mysql中建立一個數據庫quartz,並執行腳本,腳本藏在org\quartz-scheduler\quartz\2.3.2\quartz-2.3.2.jar!\org\quartz\impl\jdbcjobstore\tables_mysql_innodb.sql
,jdbcjobstore中有支持許多種數據庫的腳本,能夠按需執行。
mysql> use quartz; Database changed mysql> show tables; +--------------------------+ | Tables_in_quartz | +--------------------------+ | qrtz_blob_triggers |## blog類型存儲triggers | qrtz_calendars |## 以blog類型存儲Calendar信息 | qrtz_cron_triggers |## 存儲cron trigger信息 | qrtz_fired_triggers |## 存儲已觸發的trigger相關信息 | qrtz_job_details |## 存儲每個已配置的job details | qrtz_locks |## 存儲悲觀鎖的信息 | qrtz_paused_trigger_grps |## 存儲已暫停的trigger組信息 | qrtz_scheduler_state |## 存儲Scheduler狀態信息 | qrtz_simple_triggers |## 存儲simple trigger信息 | qrtz_simprop_triggers |## 存儲其餘幾種trigger信息 | qrtz_triggers |## 存儲已配置的trigger信息 +--------------------------+
全部的表中都含有一個SCHED_NAME
字段,對應咱們配置的scheduler-name
,相同 Scheduler-name的節點,造成一個 Quartz 集羣。
<dependencies> <!-- 實現對 Spring MVC 的自動化配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 實現對 Quartz 的自動化配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> </dependencies>
spring: datasource: quartz: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/quartz?serverTimezone=GMT%2B8 username: root password: 123456 quartz: job-store-type: jdbc # 使用數據庫存儲 scheduler-name: hyhScheduler # 相同 Scheduler 名字的節點,造成一個 Quartz 集羣 wait-for-jobs-to-complete-on-shutdown: true # 應用關閉時,是否等待定時任務執行完成。默認爲 false ,建議設置爲 true jdbc: initialize-schema: never # 是否自動使用 SQL 初始化 Quartz 表結構。這裏設置成 never ,咱們手動建立表結構。 properties: org: quartz: # JobStore 相關配置 jobStore: dataSource: quartzDataSource # 使用的數據源 class: org.quartz.impl.jdbcjobstore.JobStoreTX # JobStore 實現類 driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate tablePrefix: QRTZ_ # Quartz 表前綴 isClustered: true # 是集羣模式 clusterCheckinInterval: 1000 useProperties: false # 線程池相關配置 threadPool: threadCount: 25 # 線程池大小。默認爲 10 。 threadPriority: 5 # 線程優先級 class: org.quartz.simpl.SimpleThreadPool # 線程池類型
@Configuration public class DataSourceConfiguration { private static HikariDataSource createHikariDataSource(DataSourceProperties properties) { // 建立 HikariDataSource 對象 HikariDataSource dataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build(); // 設置線程池名 if (StringUtils.hasText(properties.getName())) { dataSource.setPoolName(properties.getName()); } return dataSource; } /** * 建立 quartz 數據源的配置對象 */ @Primary @Bean(name = "quartzDataSourceProperties") @ConfigurationProperties(prefix = "spring.datasource.quartz") // 讀取 spring.datasource.quartz 配置到 DataSourceProperties 對象 public DataSourceProperties quartzDataSourceProperties() { return new DataSourceProperties(); } /** * 建立 quartz 數據源 */ @Bean(name = "quartzDataSource") @ConfigurationProperties(prefix = "spring.datasource.quartz.hikari") @QuartzDataSource public DataSource quartzDataSource() { // 得到 DataSourceProperties 對象 DataSourceProperties properties = this.quartzDataSourceProperties(); // 建立 HikariDataSource 對象 return createHikariDataSource(properties); } }
@Component public class JobInit implements ApplicationRunner { private static final String ID = "SUMMERDAY"; @Autowired private Scheduler scheduler; @Override public void run(ApplicationArguments args) throws Exception { JobDetail jobDetail = JobBuilder.newJob(SecondJob.class) .withIdentity(ID + " 02") .storeDurably() .build(); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ? *"); // 建立任務觸發器 Trigger trigger = TriggerBuilder.newTrigger() .forJob(jobDetail) .withIdentity(ID + " 02Trigger") .withSchedule(scheduleBuilder) .startNow() //當即執行一次任務 .build(); Set<Trigger> set = new HashSet<>(); set.add(trigger); // boolean replace 表示啓動時對數據庫中的quartz的任務進行覆蓋。 scheduler.scheduleJob(jobDetail, set, true); } }
啓動測試以後,咱們的quartz任務相關信息就已經成功存儲到mysql中了。
mysql> select * from qrtz_simple_triggers; +--------------+---------------------+---------------+--------------+-----------------+-----------------+ | SCHED_NAME | TRIGGER_NAME | TRIGGER_GROUP | REPEAT_COUNT | REPEAT_INTERVAL | TIMES_TRIGGERED | +--------------+---------------------+---------------+--------------+-----------------+-----------------+ | hyhScheduler | SUMMERDAY 01Trigger | DEFAULT | -1 | 5000 | 812 | +--------------+---------------------+---------------+--------------+-----------------+-----------------+ 1 row in set (0.00 sec) mysql> select * from qrtz_cron_triggers; +--------------+---------------------+---------------+------------------+---------------+ | SCHED_NAME | TRIGGER_NAME | TRIGGER_GROUP | CRON_EXPRESSION | TIME_ZONE_ID | +--------------+---------------------+---------------+------------------+---------------+ | hyhScheduler | SUMMERDAY 02Trigger | DEFAULT | 0/10 * * * * ? * | Asia/Shanghai | +--------------+---------------------+---------------+------------------+---------------+
本文內容均爲對優秀博客及官方文檔總結而得,原文地址均已在文中參考閱讀處標註。最後,文中的代碼樣例已經所有上傳至Gitee:https://gitee.com/tqbx/springboot-samples-learn,另有其餘SpringBoot的整合哦。