乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      使用 SpringBoot2.X 實(shí)現(xiàn) Quartz 動(dòng)態(tài)任務(wù)的分布式調(diào)度

       鷹兔牛熊眼 2020-04-26

      小Hub領(lǐng)讀:

      常見(jiàn)的分布式定時(shí)任務(wù)框架:elastic-job、xxl-job、quartz ,你都熟悉嗎,今天先來(lái)學(xué)一下Quartz吧!


      作者:Sam Sho

      https://blog.csdn.net/u012228718/article/details/90041675

      見(jiàn)名知意,該篇番外主要是要解決如下幾個(gè)問(wèn)題:

      1、使用 SpringBoot2.x 版本集成 Quartz

      2、Quartz 的任務(wù)動(dòng)態(tài)實(shí)現(xiàn):

      • 調(diào)度任務(wù)可以通過(guò)頁(yè)面進(jìn)行新增、刪除、啟動(dòng)、暫定等操作

      • 任務(wù)數(shù)據(jù)使用數(shù)據(jù)庫(kù)保存

      • 任務(wù)之間實(shí)現(xiàn)簡(jiǎn)單的依賴

      3、Quartz 實(shí)現(xiàn)分布式調(diào)度,使用其本身提供的基于數(shù)據(jù)庫(kù)的實(shí)現(xiàn)

      SpringBoot2 集成 Quartz

      1、SpringBoot 不同的版本對(duì)于 Quartz 的集成有一定的差別,本文使用 2.1.2.RELEASE 版本。其實(shí)通過(guò)分析 SpringBoot 對(duì)于 Quartz 的自動(dòng)化配置源碼,也有助于我們理解 Quartz 的使用

      2、SpringBoot-2.1.2.RELEASE 版本已經(jīng)集成了對(duì)于 Quartz 的自動(dòng)化配置,其源碼路徑為 org.springframework.boot.autoconfigure.quartz

      集成簡(jiǎn)單實(shí)現(xiàn)

      Pom 依賴

      1. # Web工程

      2. <dependency>

      3. <groupId>org.springframework.boot</groupId>

      4. <artifactId>spring-boot-starter-web</artifactId>

      5. </dependency>

      6. # quartz

      7. <dependency>

      8. <groupId>org.springframework.boot</groupId>

      9. <artifactId>spring-boot-starter-quartz</artifactId>

      10. </dependency>

      11. # 數(shù)據(jù)庫(kù)JDBC

      12. <dependency>

      13. <groupId>org.springframework.boot</groupId>

      14. <artifactId>spring-boot-starter-jdbc</artifactId>

      15. </dependency>

      16. # 使用MySql

      17. <dependency>

      18. <groupId>mysql</groupId>

      19. <artifactId>mysql-connector-java</artifactId>

      20. <scope>runtime</scope>

      21. </dependency>

      編碼功能實(shí)現(xiàn)

      1、由于 Springboot2 的自動(dòng)化配置,不需要做任何配置,直接寫 JobDetail、Trigger、Job 即可實(shí)現(xiàn)

      1. # Job 實(shí)現(xiàn)

      2. @DisallowConcurrentExecution

      3. public class DemoJob extends QuartzJobBean {

      4. @Override

      5. protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

      6. System.out.println('~~ DemoJob 啟動(dòng)運(yùn)行匯總~~');

      7. }

      8. }

      9. # JobDetail、Trigger Bean配置

      10. @Configuration

      11. public class QuartzJobConfig {

      12. @Bean

      13. public JobDetailFactoryBean jobDetailFactoryBean() {

      14. JobDetailFactoryBean jobDetail = new JobDetailFactoryBean();

      15. jobDetail.setName('DemoJob');

      16. jobDetail.setGroup('DemoJob_Group');

      17. jobDetail.setJobClass(DemoJob.class);

      18. jobDetail.setDurability(true);

      19. return jobDetail;

      20. }

      21. @Bean

      22. public CronTriggerFactoryBean cronTriggerFactoryBean() {

      23. CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();

      24. trigger.setJobDetail(jobDetailFactoryBean().getObject());

      25. trigger.setCronExpression('*/10 * * * * ?');

      26. trigger.setName('DemoJob');

      27. trigger.setMisfireInstruction(0);

      28. return trigger;

      29. }

      30. }

      2、這樣就實(shí)現(xiàn)了 SpringBoot2.x 版本集成 Quartz 功能,在進(jìn)行下一步之前,我們先對(duì)自動(dòng)化配置的源碼簡(jiǎn)單分析一下。

      自動(dòng)配置實(shí)現(xiàn)分析

      SpringBoot 關(guān)于 Quartz 的自動(dòng)配置的類一共有 6 個(gè),分別為:

      1、 JobStoreType:是一個(gè)枚舉類,定義了 jobsStore 的類型,基于內(nèi)存和數(shù)據(jù)庫(kù)

      2、 QuartzAutoConfiguration:自動(dòng)配置類,配置了 Quartz 的主要組件,如 SchedulerFactoryBean

      3、 QuartzDataSource:是一個(gè)注解類。如果需要注入 Quartz 配置的數(shù)據(jù)庫(kù)操作類,需要使用此注解標(biāo)注。參考 QuartzAutoConfiguration中的用法

      4、 QuartzDataSourceInitializer:該類主要用于數(shù)據(jù)源初始化后的一些操作,根據(jù)不同平臺(tái)類型的數(shù)據(jù)庫(kù)進(jìn)行選擇不同的數(shù)據(jù)庫(kù)腳本

      5、 QuartzProperties:該類對(duì)應(yīng)了在 application.yml配置文件以 spring.quartz開(kāi)頭的相關(guān)配置

      6、 SchedulerFactoryBeanCustomizer:在自動(dòng)配置的基礎(chǔ)上自定義配置需要實(shí)現(xiàn)的此接口。

      自動(dòng)化配置分析 QuartzAutoConfiguration

      1、初始化注入任務(wù)以及配置:構(gòu)造函數(shù)實(shí)現(xiàn)

      • 注入了屬性配置文件類: QuartzProperties

      • 注入了自定義擴(kuò)展配置: SchedulerFactoryBeanCustomizer

      • 注入了 Quartz 的任務(wù)組件: JobDetail、 Trigger、 Calendar。所以我們只需要進(jìn)行 JobDetail、Trigger Bean 配置,會(huì)自動(dòng)注入進(jìn) QuartzAutoConfiguration類中,這邊是通過(guò) ObjectProvider的使用實(shí)現(xiàn)的。

      1. public QuartzAutoConfiguration(QuartzProperties properties,

      2. ObjectProvider<SchedulerFactoryBeanCustomizer> customizers,

      3. ObjectProvider<JobDetail[]> jobDetails,

      4. ObjectProvider<Map<String, Calendar>> calendars,

      5. ObjectProvider<Trigger[]> triggers, ApplicationContext applicationContext) {

      6. this.properties = properties;

      7. this.customizers = customizers;

      8. this.jobDetails = jobDetails.getIfAvailable();

      9. this.calendars = calendars.getIfAvailable();

      10. this.triggers = triggers.getIfAvailable();

      11. this.applicationContext = applicationContext;

      12. }

      2、配置 SchedulerFactoryBean 的詳細(xì)信息。這個(gè)類是一個(gè) FactoryBean。

      • 配置 JobFactory,內(nèi)部設(shè)置了 applicationContext與 spring 容器結(jié)合

      • 配置各種屬性,是通過(guò) QuartzProperties類實(shí)現(xiàn)

      • 配置注入進(jìn)來(lái)的 JobDetail、 Trigger、 Calendar

      • 配置自定配置,是通過(guò) SchedulerFactoryBeanCustomizer實(shí)現(xiàn)。這邊包括自定義,也包括基于數(shù)據(jù)庫(kù)實(shí)現(xiàn)的 JobStore配置。

      1. @Bean

      2. @ConditionalOnMissingBean

      3. public SchedulerFactoryBean quartzScheduler() {

      4. # 配置 `JobFactory`

      5. SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();

      6. SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();

      7. jobFactory.setApplicationContext(this.applicationContext);

      8. schedulerFactoryBean.setJobFactory(jobFactory);

      9. # 開(kāi)始配置各種屬性

      10. if (this.properties.getSchedulerName() != null) {

      11. schedulerFactoryBean.setSchedulerName(this.properties.getSchedulerName());

      12. }

      13. schedulerFactoryBean.setAutoStartup(this.properties.isAutoStartup());

      14. schedulerFactoryBean

      15. .setStartupDelay((int) this.properties.getStartupDelay().getSeconds());

      16. schedulerFactoryBean.setWaitForJobsToCompleteOnShutdown(

      17. this.properties.isWaitForJobsToCompleteOnShutdown());

      18. schedulerFactoryBean

      19. .setOverwriteExistingJobs(this.properties.isOverwriteExistingJobs());

      20. if (!this.properties.getProperties().isEmpty()) {

      21. schedulerFactoryBean

      22. .setQuartzProperties(asProperties(this.properties.getProperties()));

      23. }

      24. # 配置 jobDetails、triggers等

      25. if (this.jobDetails != null && this.jobDetails.length > 0) {

      26. schedulerFactoryBean.setJobDetails(this.jobDetails);

      27. }

      28. if (this.calendars != null && !this.calendars.isEmpty()) {

      29. schedulerFactoryBean.setCalendars(this.calendars);

      30. }

      31. if (this.triggers != null && this.triggers.length > 0) {

      32. schedulerFactoryBean.setTriggers(this.triggers);

      33. }

      34. # 自定義配置

      35. customize(schedulerFactoryBean);

      36. return schedulerFactoryBean;

      37. }

      3、基于數(shù)據(jù)庫(kù)實(shí)現(xiàn)的 JobStore 配置,內(nèi)部類 JdbcStoreTypeConfiguration

      • @ConditionalOnSingleCandidate(DataSource.class) 指定 pring 容器中有且只有一個(gè)指明的 DataSourceBean 時(shí)生效

      • 通過(guò) dataSourceCustomizer方法實(shí)現(xiàn) schedulerFactoryBean的數(shù)據(jù)庫(kù)相關(guān)配置,該方法返回一個(gè) SchedulerFactoryBeanCustomizer。

      • 配置 QuartzDataSourceInitializer 數(shù)據(jù)庫(kù)初始化 Bean

      4、通過(guò)后置工廠處理器 DataSourceInitializerSchedulerDependencyPostProcessor 實(shí)現(xiàn)對(duì)于 QuartzDataSourceInitializer這個(gè) Bean 的依賴關(guān)系(dependsOn)

      1. @Bean

      2. @Order(0)

      3. public SchedulerFactoryBeanCustomizer dataSourceCustomizer(

      4. QuartzProperties properties, DataSource dataSource,

      5. @QuartzDataSource ObjectProvider<DataSource> quartzDataSource,

      6. ObjectProvider<PlatformTransactionManager> transactionManager) {

      7. return (schedulerFactoryBean) -> {

      8. # 判斷是否為 JobStore

      9. if (properties.getJobStoreType() == JobStoreType.JDBC) {

      10. # 獲取 DataSource

      11. DataSource dataSourceToUse = getDataSource(dataSource, quartzDataSource);

      12. # 配置 DataSource 和 TransactionManager管理

      13. schedulerFactoryBean.setDataSource(dataSourceToUse);

      14. PlatformTransactionManager txManager = transactionManager.getIfUnique();

      15. if (txManager != null) {

      16. schedulerFactoryBean.setTransactionManager(txManager);

      17. }

      18. }

      19. };

      20. }

      支持功能配置 QuartzProperties

      1、 @ConfigurationProperties('spring.quartz') 以 spring.quartz開(kāi)頭的配置

      2、SpringBoot 已經(jīng)做了相應(yīng)的默認(rèn)值處理,即使不做任何配置,也是沒(méi)有問(wèn)題的。

      3、比較簡(jiǎn)單,直接貼碼。屬性的具體含義,任務(wù)調(diào)度框架(3)Quartz 簡(jiǎn)單使用

      1. spring:

      2. quartz:

      3. scheduler-name: springboot-quartz-jdbc-dynamic

      4. auto-startup: false

      5. startup-delay: 5s

      6. overwrite-existing-jobs: false

      7. wait-for-jobs-to-complete-on-shutdown: true

      8. job-store-type: memory

      9. # jdbc:

      10. # initialize-schema: embedded

      11. # schema: classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql

      12. # comment-prefix: --

      13. properties: {

      14. org.quartz.scheduler.instanceName: springboot-quartz-jdbc-dynamic,

      15. org.quartz.scheduler.instanceId: AUTO,

      16. org.quartz.threadPool.class: org.springframework.scheduling.quartz.SimpleThreadPoolTaskExecutor,

      17. org.quartz.threadPool.threadCount: 25,

      18. org.quartz.threadPool.threadPriority: 5,

      19. org.quartz.jobStore.misfireThreshold: 60000,

      20. # org.quartz.jobStore.tablePrefix: QRTZ_,

      21. # org.quartz.jobStore.isClustered: true,

      22. # org.quartz.jobStore.clusterCheckinInterval: 20000,

      23. # org.quartz.jobStore.maxMisfiresToHandleAtATime: 1,

      24. # org.quartz.jobStore.txIsolationLevelSerializable: false

      25. }

      小結(jié)

      1、至此,我們完成了 SpringBoot 與 Quartz 的集成,并且簡(jiǎn)單運(yùn)行了我們的調(diào)度任務(wù)

      2、簡(jiǎn)單分析了 SpringBoot 對(duì)于 Quartz 的自動(dòng)配置,由于各個(gè)版本的差別,這邊使用的是 SpringBoot-2.1.2.RELEASE

      Quartz 實(shí)現(xiàn)分布式調(diào)度

      回顧分析

      任務(wù)調(diào)度框架(4)Quartz 分布式實(shí)現(xiàn) 已經(jīng)對(duì) Quartz 自身的分布式實(shí)現(xiàn)做了簡(jiǎn)單的介紹,這邊主要基于 SpringBoot 怎么做。

      配置簡(jiǎn)單實(shí)現(xiàn)

      1、上述完成的 SpringBoot 與 Quartz 的集成,可以看到有幾個(gè)先關(guān)的配置:

      • job-store-type 可以選擇 JDBC完成分布式 JdbcJobStore切換

      • jdbc.XXX 主要是對(duì)于初始化 SQL 的配置。樹(shù)妖是對(duì)于 quartz 提供的 11 張表的初始化 sql

      • 對(duì)于 JdbcJobStore 的一些特殊配置,如表前綴、集群指定、數(shù)據(jù)庫(kù)檢查等,基于 RamJobStore時(shí),這些是不允許配置的。

      1. spring:

      2. quartz:

      3. job-store-type: memory

      4. jdbc:

      5. initialize-schema: embedded

      6. schema: classpath:org/quartz/impl/jdbcjobstore/tables_@@platform@@.sql

      7. comment-prefix: --

      8. properties: {

      9. org.quartz.jobStore.misfireThreshold: 60000,

      10. org.quartz.jobStore.tablePrefix: QRTZ_,

      11. org.quartz.jobStore.isClustered: true,

      12. org.quartz.jobStore.clusterCheckinInterval: 20000,

      13. org.quartz.jobStore.maxMisfiresToHandleAtATime: 1,

      14. org.quartz.jobStore.txIsolationLevelSerializable: false

      15. }

      2、以上就配置好了 Quartz 實(shí)現(xiàn)分布式調(diào)度,就是這么簡(jiǎn)單

      3、【注意】在嘗試的時(shí)候, jdbc.xxx配置沒(méi)有生效,個(gè)人是自己手動(dòng)初始化的表。

      Quartz 的任務(wù)動(dòng)態(tài)實(shí)現(xiàn)

      1、以上我們簡(jiǎn)單完成了 SpringBoot 集成與基于 JDBC 的分布式,但是我們的任務(wù)還是基于 Bean 配置的:

      • 新增任務(wù)需要手動(dòng)硬編碼,增加 JobDetail、 Trigger的 Bean 配置

      • 上線后的任務(wù)無(wú)法修改,需要修改代碼,停止應(yīng)用

      2、所以,所謂的動(dòng)態(tài)任務(wù)主要是三個(gè)問(wèn)題:

      • 任務(wù)數(shù)據(jù)使用數(shù)據(jù)庫(kù)保存,包括任務(wù)的基本信息與 trigger 信息

      • 調(diào)度任務(wù)可以通過(guò)頁(yè)面進(jìn)行新增、修改、刪除、啟動(dòng)、暫停、重啟等操作

      • 任務(wù)之間實(shí)現(xiàn)簡(jiǎn)單的依賴,如 A 任務(wù)依賴于 B 任務(wù),那么 A 任務(wù)必須等到 B 任務(wù)執(zhí)行完成才會(huì)自動(dòng)執(zhí)行

      數(shù)據(jù)使用數(shù)據(jù)庫(kù)保存

      1、簡(jiǎn)單,把任務(wù)調(diào)度分為兩個(gè)模塊:

      • 基本任務(wù)(BatchTask)與任務(wù)計(jì)劃(BatchSchedule),BatchTask 與 BatchSchedule 是一對(duì)多關(guān)系,代替 Quartz 中 jobGroup 的概念。

      • 任務(wù)計(jì)劃(BatchSchedule) 中可能需要用到配置的一些參數(shù),定義任務(wù)計(jì)劃參數(shù)(BatchScheduleParam)

      2、具體的實(shí)體如下,數(shù)據(jù)庫(kù)相關(guān)表結(jié)構(gòu)略

      • 基本任務(wù)(BatchTask)

      1. public class BatchTask extends AbstractDataEntity {

      2. /**

      3. * 任務(wù)編碼:唯一

      4. */

      5. private String code;

      6. /**

      7. * 任務(wù)名稱

      8. */

      9. private String name;

      10. /**

      11. * 任務(wù)描述

      12. */

      13. private String description;

      14. /**

      15. * 前置任務(wù)

      16. */

      17. private List<BatchTask> previous;

      18. }

      • 任務(wù)計(jì)劃(BatchSchedule)

      1. public class BatchSchedule extends AbstractDataEntity {

      2. /**

      3. * 計(jì)劃編碼

      4. */

      5. private String code;

      6. /**

      7. * 計(jì)劃名稱

      8. */

      9. private String name;

      10. /**

      11. * 計(jì)劃狀態(tài): 整個(gè)生命周期狀態(tài)

      12. */

      13. private Integer status;

      14. /**

      15. * 執(zhí)行表達(dá)式類型

      16. */

      17. private Integer cronType;

      18. /**

      19. * 執(zhí)行表達(dá)式

      20. */

      21. private String cronExpression;

      22. /**

      23. * 描述

      24. */

      25. private String description;

      26. /**

      27. * 處理業(yè)務(wù)類

      28. */

      29. private String interfaceName;

      30. /**

      31. * 任務(wù)編碼(任務(wù)組的概念)

      32. */

      33. private String taskCode;

      34. /**

      35. * 開(kāi)始時(shí)間(最近)

      36. */

      37. private Date startDate;

      38. /**

      39. * 結(jié)束時(shí)間(最近)

      40. */

      41. private Date endDate;

      42. /**

      43. * 前置計(jì)劃列表

      44. */

      45. private List<BatchSchedule> dependencies;

      46. /**

      47. * 參數(shù)列表

      48. */

      49. private List<BatchScheduleParam> params;

      50. }

      • 計(jì)劃參數(shù)(BatchScheduleParam)

      1. public class BatchScheduleParam {

      2. /**

      3. * 任務(wù)計(jì)劃ID

      4. */

      5. private String scheduleId;

      6. /**

      7. * 任務(wù)計(jì)劃code

      8. */

      9. private String scheduleCode;

      10. /**

      11. * 參數(shù)名

      12. */

      13. private String paramName;

      14. /**

      15. * 參數(shù)值

      16. */

      17. private String paramValue;

      18. }

      3、有了這些實(shí)體,無(wú)非就是根據(jù)實(shí)體對(duì)基本任務(wù)與任務(wù)計(jì)劃做 CRUD,這個(gè)比較簡(jiǎn)單,不贅述。

      任務(wù)計(jì)劃的動(dòng)態(tài)管理

      手動(dòng)配置實(shí)現(xiàn)的原理

      1、手動(dòng)配置是需要編碼實(shí)現(xiàn) JobDetailFactoryBean、 CronTriggerFactoryBean,然后通過(guò) SpringBoot 的自動(dòng)化配置,設(shè)置到
      schedulerFactoryBean對(duì)象的對(duì)應(yīng)屬性中。

      1. schedulerFactoryBean.setJobDetails(this.jobDetails);

      2. schedulerFactoryBean.setTriggers(this.triggers);

      2、 SchedulerFactoryBean源碼中,通過(guò) afterPropertiesSet()方法中方法,注冊(cè)到 Scheduler對(duì)象中

      • 最終核心是通過(guò) Scheduler.scheduleJob(jobDetail,trigger);添加

      1. // Initialize the Scheduler instance...

      2. this.scheduler = prepareScheduler(prepareSchedulerFactory());

      3. try {

      4. registerListeners();

      5. registerJobsAndTriggers(); # 注冊(cè)JobsAndTriggers

      6. }

      7. protected void registerJobsAndTriggers() throws SchedulerException {

      8. // Register JobDetails.

      9. if (this.jobDetails != null) {

      10. for (JobDetail jobDetail : this.jobDetails) {

      11. addJobToScheduler(jobDetail);

      12. }

      13. }

      14. // Register Triggers.

      15. if (this.triggers != null) {

      16. for (Trigger trigger : this.triggers) {

      17. addTriggerToScheduler(trigger);

      18. }

      19. }

      20. }

      21. private boolean addJobToScheduler(JobDetail jobDetail) throws SchedulerException {

      22. if (this.overwriteExistingJobs || getScheduler().getJobDetail(jobDetail.getKey()) == null) {

      23. # 最終是通過(guò)Scheduler.addJob(jobDetail, true); 添加

      24. getScheduler().addJob(jobDetail, true);

      25. return true;

      26. }

      27. else {

      28. return false;

      29. }

      30. }

      31. private boolean addTriggerToScheduler(Trigger trigger) throws SchedulerException {

      32. # 最終是通過(guò)Scheduler.scheduleJob(jobDetail, trigger); 添加(只是一部分功能)

      33. getScheduler().scheduleJob(jobDetail, trigger);

      34. }

      動(dòng)態(tài)管理:創(chuàng)建計(jì)劃任務(wù)引擎類

      1、 Scheduler 在 SpringBoot 中已經(jīng)通過(guò) SchedulerFactoryBean自動(dòng)配置好了,直接注入即可使用。 2、具體可以 參考源碼

      1. public class QuartzScheduleEngine {

      2. @Autowired

      3. private Scheduler scheduler;

      4. /**

      5. * 新增計(jì)劃任務(wù): 主要是添加 jobDetail 和 trigger

      6. *

      7. * @param batchSchedule

      8. */

      9. public Date addJob(BatchSchedule batchSchedule) throws Exception {

      10. String cronExpression = batchSchedule.getCronExpression();

      11. String name = batchSchedule.getCode();

      12. String group = batchSchedule.getTaskCode();

      13. String interfaceName = batchSchedule.getInterfaceName();

      14. // 校驗(yàn)數(shù)據(jù)

      15. this.checkNotNull(batchSchedule);

      16. // 添加 1-JobDetail

      17. // 校驗(yàn) JobDetail 是否存在

      18. JobKey jobKey = JobKey.jobKey(name, group);

      19. if (scheduler.checkExists(jobKey)) {

      20. if (Strings.isNullOrEmpty(cronExpression)) {

      21. // 已經(jīng)存在并且執(zhí)行一次,立即執(zhí)行

      22. scheduler.triggerJob(jobKey);

      23. } else {

      24. throw new Exception('任務(wù)計(jì)劃 JobKey 已經(jīng)在執(zhí)行隊(duì)列中,不需要重復(fù)啟動(dòng)');

      25. }

      26. } else {

      27. // 構(gòu)建 JobDetail

      28. Class<? extends Job> jobClazz = (Class<? extends Job>) Class.forName(interfaceName);

      29. JobDetail jobDetail = JobBuilder.newJob(jobClazz).withIdentity(jobKey).build();

      30. jobDetail.getJobDataMap().put(BatchSchedule.SCHEDULE_KEY, batchSchedule.toString());

      31. // 添加 2-Trigger

      32. // 校驗(yàn) Trigger 是否存在

      33. TriggerKey triggerKey = TriggerKey.triggerKey(name, group);

      34. Trigger trigger = scheduler.getTrigger(triggerKey);

      35. if (Objects.nonNull(trigger)) {

      36. throw new Exception('任務(wù)計(jì)劃 Trigger 已經(jīng)在執(zhí)行隊(duì)列中,不需要重復(fù)啟動(dòng)');

      37. }

      38. // 構(gòu)建 Trigger

      39. trigger = getTrigger(cronExpression, triggerKey);

      40. return scheduler.scheduleJob(jobDetail, trigger);

      41. }

      42. return new Date();

      43. }

      44. /**

      45. * 修改

      46. *

      47. * @param batchSchedule

      48. */

      49. public void updateCronExpression(BatchSchedule batchSchedule) throws Exception {

      50. updateJobCronExpression(batchSchedule);

      51. }

      52. /**

      53. * 更新Job的執(zhí)行表達(dá)式

      54. *

      55. * @param batchSchedule

      56. * @throws SchedulerException

      57. */

      58. public Date updateJobCronExpression(BatchSchedule batchSchedule) throws SchedulerException {

      59. checkNotNull(batchSchedule);

      60. String name = batchSchedule.getCode();

      61. String group = batchSchedule.getTaskCode();

      62. TriggerKey triggerKey = TriggerKey.triggerKey(name, group);

      63. // 在隊(duì)列中才需要修改

      64. if (scheduler.checkExists(triggerKey)) {

      65. // 構(gòu)建 Trigger

      66. String cronExpression = batchSchedule.getCronExpression();

      67. Trigger trigger = this.getTrigger(cronExpression, triggerKey);

      68. return scheduler.rescheduleJob(triggerKey, trigger);

      69. }

      70. return null;

      71. }

      72. /**

      73. * 構(gòu)建 Trigger

      74. *

      75. * @param cronExpression

      76. * @param triggerKey

      77. * @return

      78. */

      79. private Trigger getTrigger(String cronExpression, TriggerKey triggerKey) {

      80. Trigger trigger;

      81. if (Strings.isNullOrEmpty(cronExpression.trim())) {

      82. trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).build();

      83. } else {

      84. cronExpression = cronExpression.replaceAll('#', ' ');

      85. CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

      86. trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();

      87. }

      88. return trigger;

      89. }

      90. /**

      91. * 暫停計(jì)劃任務(wù)

      92. *

      93. * @param batchSchedule

      94. */

      95. public void pauseJob(BatchSchedule batchSchedule) throws Exception {

      96. checkNotNull(batchSchedule);

      97. JobKey jobKey = JobKey.jobKey(batchSchedule.getCode(), batchSchedule.getTaskCode());

      98. if (!scheduler.checkExists(jobKey)) {

      99. throw new Exception('任務(wù)計(jì)劃不在執(zhí)行隊(duì)列中,不能暫停');

      100. }

      101. scheduler.pauseJob(jobKey);

      102. }

      103. /**

      104. * 從暫停中恢復(fù)

      105. *

      106. * @param batchSchedule

      107. */

      108. public void resumeJob(BatchSchedule batchSchedule) throws Exception {

      109. checkNotNull(batchSchedule);

      110. JobKey jobKey = JobKey.jobKey(batchSchedule.getCode(), batchSchedule.getTaskCode());

      111. if (!scheduler.checkExists(jobKey)) {

      112. throw new Exception('任務(wù)計(jì)劃不在執(zhí)行隊(duì)列中,不能恢復(fù)');

      113. }

      114. scheduler.resumeJob(jobKey);

      115. }

      116. /**

      117. * 刪除計(jì)劃任務(wù)

      118. *

      119. * @param batchSchedule

      120. */

      121. public boolean deleteJob(BatchSchedule batchSchedule) throws SchedulerException {

      122. boolean flag = true;

      123. checkNotNull(batchSchedule);

      124. JobKey jobKey = JobKey.jobKey(batchSchedule.getCode(), batchSchedule.getTaskCode());

      125. if (scheduler.checkExists(jobKey)) {

      126. flag = scheduler.deleteJob(jobKey);

      127. }

      128. return flag;

      129. }

      130. /**

      131. * 添加任務(wù)監(jiān)聽(tīng)

      132. *

      133. * @param jobListener

      134. * @param matcher

      135. * @throws SchedulerException

      136. */

      137. public void addJobListener(JobListener jobListener, Matcher<JobKey> matcher) throws SchedulerException {

      138. scheduler.getListenerManager().addJobListener(jobListener, matcher);

      139. }

      140. /**

      141. * 執(zhí)行一次(可用于測(cè)試)

      142. *

      143. * @param batchSchedule

      144. */

      145. public void runJobOnce(BatchSchedule batchSchedule) throws SchedulerException {

      146. checkNotNull(batchSchedule);

      147. JobKey jobKey = JobKey.jobKey(batchSchedule.getCode(), batchSchedule.getTaskCode());

      148. scheduler.triggerJob(jobKey);

      149. }

      150. private void checkNotNull(BatchSchedule batchSchedule) {

      151. Preconditions.checkNotNull(batchSchedule, '計(jì)劃為空');

      152. Preconditions.checkState(!StringUtils.isEmpty(batchSchedule.getCode()), '計(jì)劃編號(hào)為空');

      153. Preconditions.checkState(!StringUtils.isEmpty(batchSchedule.getTaskCode()), '計(jì)劃所屬任務(wù)為空');

      154. Preconditions.checkState(!StringUtils.isEmpty(batchSchedule.getInterfaceName()), '任務(wù)執(zhí)行業(yè)務(wù)類為空');

      155. }

      156. public SchedulerMetaData getMetaData() throws SchedulerException {

      157. SchedulerMetaData metaData = scheduler.getMetaData();

      158. return metaData;

      159. }

      160. }

      任務(wù)狀態(tài)與計(jì)劃依賴

      1、使用 JobListener實(shí)現(xiàn),需要自定義配置的支持

      1. public class CustomGlobalJobListener extends JobListenerSupport {

      2. @Override

      3. public String getName() {

      4. return this.getClass().getName();

      5. }

      6. /**

      7. * Scheduler 在 JobDetail 將要被執(zhí)行時(shí)調(diào)用這個(gè)方法。

      8. *

      9. * @param context

      10. */

      11. @Override

      12. public void jobToBeExecuted(JobExecutionContext context) {

      13. getLog().debug('計(jì)劃 {} : ~~~ 【RUNNING】 更新正在運(yùn)行中狀態(tài) ~~~ ');

      14. }

      15. /**

      16. * Scheduler 在 JobDetail 即將被執(zhí)行,但又被 TriggerListener 否決了時(shí)調(diào)用這個(gè)方法

      17. *

      18. * @param context

      19. */

      20. @Override

      21. public void jobExecutionVetoed(JobExecutionContext context) {

      22. }

      23. /**

      24. * Scheduler 在 JobDetail 被執(zhí)行之后調(diào)用這個(gè)方法

      25. *

      26. * @param context

      27. * @param jobException

      28. */

      29. @Override

      30. public void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {

      31. getLog().debug('計(jì)劃 {} : ~~~ 【COMPLETE | ERROR】 更新已經(jīng)結(jié)束狀態(tài) ~~~ ');

      32. // 喚醒子任務(wù)

      33. batchScheduleService.notifyChildren(scheduleJob);

      34. }

      35. }

      2、自定義實(shí)現(xiàn),可以實(shí)現(xiàn) SchedulerFactoryBeanCustomizer接口

      1. @Configuration

      2. public class SchedulerFactoryBeanCustomizerConfig implements SchedulerFactoryBeanCustomizer {

      3. @Bean

      4. public CustomGlobalJobListener globalJobListener() {

      5. return new CustomGlobalJobListener();

      6. }

      7. @Override

      8. public void customize(SchedulerFactoryBean schedulerFactoryBean) {

      9. schedulerFactoryBean.setGlobalJobListeners(globalJobListener());

      10. }

      11. }

      3、計(jì)劃依賴:

      • 如計(jì)劃有依賴其他計(jì)劃,則該計(jì)劃一般不允許手動(dòng)運(yùn)行,需要等待所依賴的計(jì)劃完成后在監(jiān)聽(tīng)器中自動(dòng)喚醒

      • 目前只簡(jiǎn)單實(shí)現(xiàn)了單個(gè)計(jì)劃依賴,沒(méi)有實(shí)現(xiàn)復(fù)雜功能。后期可以擴(kuò)展:多計(jì)劃依賴,依賴排序等功能。

      小結(jié)

      至此,Quartz 的任務(wù)動(dòng)態(tài)實(shí)現(xiàn)已經(jīng)完成,主要可以分為三個(gè)部分:

      1、任務(wù)與計(jì)劃定義,使用數(shù)據(jù)庫(kù)保存

      2、動(dòng)態(tài)計(jì)劃的管理,使用 Quartz 本身的 API 實(shí)現(xiàn)

      3、任務(wù)計(jì)劃狀態(tài)監(jiān)控,使用 JobListener監(jiān)聽(tīng)器實(shí)現(xiàn)

      4、計(jì)劃依賴,使用 JobListener監(jiān)聽(tīng)器實(shí)現(xiàn)。

      參考

      1、lotso-web:使用 SpringBoot2.X 實(shí)現(xiàn) Quartz 動(dòng)態(tài)任務(wù)的分布式調(diào)度

      2、源碼地址 LearningJobSchedule



      (完)

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多