SpringBoot系列:Spring Boot集成定時任務Quartz

  • 2019 年 11 月 10 日
  • 筆記

一、關於Quartz

Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,它可以與J2EE與J2SE應用程式相結合也可以單獨使用。在java企業級應用中,Quartz是使用最廣泛的定時調度框架。

在Quartz中的主要概念:

  • Scheduler:調度任務的主要API
  • ScheduleBuilder:用於構建Scheduler,例如其簡單實現類SimpleScheduleBuilder
  • Job:調度任務執行的介面,也即定時任務執行的方法
  • JobDetail:定時任務作業的實例
  • JobBuilder:關聯具體的Job,用於構建JobDetail
  • Trigger:定義調度執行計劃的組件,即定時執行
  • TriggerBuilder:構建Trigger

一、Quartz演示示例

在SpringBoot中,我們需要引入quartz的依賴。

 <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>

首先定義定時具體執行邏輯Job,創建類QuartzJob1,這裡集繼承QuartzJobBean實現executeInternal即可,該方法即定時執行任務邏輯,這裡簡單列印了下當前時間。

public class QuartzJob1 extends QuartzJobBean {        @Override      protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {          SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");          System.out.println("QuartzJob1----" + sdf.format(new Date()));      }    }

然後創建QuartzConfig,接著定義JobDetail,JobDetail由JobBuilder構建,同時關聯了任務QuartzJob1。

@Configuration  public class QuartzConfig {        @Bean      public JobDetail jobDetail1(){          return JobBuilder.newJob(QuartzJob1.class).storeDurably().build();      }    }

最後我們需要定義定時調度Trigger,簡單實現類SimpleScheduleBuilder用於構建Scheduler,TriggerBuilder則用於構建Trigger,

@Configuration  public class QuartzConfig {        @Bean      public JobDetail jobDetail1(){          return JobBuilder.newJob(QuartzJob1.class).storeDurably().build();      }        @Bean      public Trigger trigger1(){          SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()                  .withIntervalInSeconds(1) //每一秒執行一次                  .repeatForever(); //永久重複,一直執行下去          return TriggerBuilder.newTrigger()                  .forJob(jobDetail1())                  .withSchedule(scheduleBuilder)                  .build();      }    }

這樣一個Quartz定時任務就配置完成了。

其實Job的定義也可以使用內部類,這樣可以省去Job類的創建,例如下面定時任務2 jobDetail2和trigger2。

@Bean  public JobDetail jobDetail2(){      QuartzJobBean quartzJob2 = new QuartzJobBean() {          @Override          protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {              SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");              System.out.println("內部類quartzJob2----" + sdf.format(new Date()));          }      };      return JobBuilder.newJob(quartzJob2.getClass()).storeDurably().build();  }    @Bean  public Trigger trigger2(){      //JobDetail的bean注入不能省略      //JobDetail jobDetail3 = JobBuilder.newJob(QuartzJob2.class).storeDurably().build();      SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()              .withIntervalInSeconds(2) //每2秒執行一次              .repeatForever(); //永久重複,一直執行下去      return TriggerBuilder.newTrigger()              .forJob(jobDetail2())              .withSchedule(scheduleBuilder).build();  }

啟動程式,我們就可以看到控制台的時間輸出了。

同時Quartz是支援數據持久化的,可以將定時調度資訊持久化到資料庫。

選擇持久化到資料庫,我們需要創建對應的表,建表語句可以在Quartz官網進行下載,解壓後在docsdbTables目錄下尋找對應資料庫的SQL腳本。

為了方便,我也將該文件放在了項目源碼resources里。

操作資料庫,我們引入相關的依賴。若有ORM框架,例如mybatis,hibernate或者jpa,則無需再引入jdbc依賴。

<!--mysql連接-->  <dependency>      <groupId>mysql</groupId>      <artifactId>mysql-connector-java</artifactId>      <scope>runtime</scope>  </dependency>    <!--druid連接池-->  <dependency>      <groupId>com.alibaba</groupId>      <artifactId>druid-spring-boot-starter</artifactId>      <version>1.1.10</version>  </dependency>    <!--jdbc依賴-->  <dependency>      <groupId>org.springframework.boot</groupId>      <artifactId>spring-boot-starter-jdbc</artifactId>  </dependency>

在application.yml配置文件中,我們對quartz持久化方式進行聲明。

server:    port: 10900    spring:    profiles:      active: dev    quartz:      job-store-type: jdbc #持久化到資料庫      properties:        org:          quartz:            datasource:              # 新版驅動從com.mysql.jdbc.Driver變更為com.mysql.cj.jdbc.Driver              driver-class-name: com.mysql.cj.jdbc.Driver              # 數據源需要添加時間標準和指定編碼格式解決亂碼 You must configure either the server or JDBC driver (via the serverTimezone configuration property) to use a more specifc time zone value if you want to utilize time zone support.              url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC              username: root              password: 1234            scheduler:              instancName: clusteredScheduler              instanceId: AUTO            jobStore:              class: org.quartz.impl.jdbcjobstore.JobStoreTX              driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #StdJDBCDelegate說明支援集群              tablePrefix: QRTZ_              isClustered: true              clusterCheckinInterval: 1000              useProperties: false            threadPool:              class: org.quartz.simpl.SimpleThreadPool              threadCount: 20              threadPriority: 5

這裡主要就是job-store-type: jdbc,表示持久化到資料庫,然後就是數據源,由於該演示項目沒有其他ORM的數據源,所以這裡將數據源資訊定義在了quartz節點下的datasource節點,如果已經存在,可使用同一個屬性配置,當然最關鍵的是QuartzDataSource聲明。

這裡關鍵的是@QuartzDataSource,這個要和項目中已經存在的數據源區分開。

//Error:EmbeddedDatabaseType class not found,Druid數據源初始化需要引入spring-jdbc依賴,JPA或mybatis依賴已經包含該依賴  @Bean  @QuartzDataSource  @ConfigurationProperties(prefix = "spring.quartz.properties.org.quartz.datasource")  DataSource quartzDataSource(){      return DruidDataSourceBuilder.create().build();  }

這樣持久化就已經配置好了,我們執行sql,再啟動項目,啟動完成後,我們可以看到資料庫中已經有我們的定時調度數據了。

源碼地址:https://github.com/imyanger/springboot-project/tree/master/p25-springboot-quartz