Spring Boot series: Spring Boot integrated timing task Quartz

Posted by les4017 on Sat, 09 Nov 2019 16:49:31 +0100

I. about Quartz

Quartz is another open source project of OpenSymphony open source organization in Job scheduling field. It can be combined with J2EE and J2SE applications or used alone. In java enterprise applications, quartz is the most widely used timing scheduling framework.

Main concepts in Quartz:

  • Scheduler: the main API for scheduling tasks
  • ScheduleBuilder: used to build a Scheduler, such as its simple implementation class SimpleScheduleBuilder
  • Job: interface for scheduling task execution, i.e. method for timing task execution
  • JobDetail: an instance of a scheduled task job
  • Job builder: associate specific jobs to build jobdetails
  • Trigger: the component that defines the schedule execution plan, i.e. scheduled execution
  • Trigger Builder: build trigger

I. Quartz demonstration example

In spring boot, we need to introduce quartz dependency.

 <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--quartz Scheduled scheduling dependency-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

First of all, define the timed concrete execution logic Job and create the class QuartzJob1. Here, inherit the QuartzJobBean to implement executeInternal. This method is the timed execution task logic. Here, the current time is simply printed.

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()));
    }

}

Then create QuartzConfig, then define JobDetail, which is built by JobBuilder and associated with task QuartzJob1.

@Configuration
public class QuartzConfig {

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

Finally, we need to define a scheduled scheduling Trigger. The simple implementation class SimpleScheduleBuilder is used to build the Scheduler, and the Trigger builder is used to build the 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) //Every second
                .repeatForever(); //Repeat forever, carry on
        return TriggerBuilder.newTrigger()
                .forJob(jobDetail1())
                .withSchedule(scheduleBuilder)
                .build();
    }
    
}

This completes the configuration of a Quartz timing task.

In fact, the definition of Job can also use internal classes, which can save the creation of Job classes, such as the following scheduled tasks 2 jobDetail2 and 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("Inner class quartzJob2----" + sdf.format(new Date()));
        }
    };
    return JobBuilder.newJob(quartzJob2.getClass()).storeDurably().build();
}

@Bean
public Trigger trigger2(){
    //bean injection of JobDetail cannot be omitted
    //JobDetail jobDetail3 = JobBuilder.newJob(QuartzJob2.class).storeDurably().build();
    SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
            .withIntervalInSeconds(2) //Every 2 seconds
            .repeatForever(); //Repeat forever, carry on
    return TriggerBuilder.newTrigger()
            .forJob(jobDetail2())
            .withSchedule(scheduleBuilder).build();
}

Start the program, and we can see the time output of the console.

At the same time, Quartz supports data persistence and can persist scheduled scheduling information to the database.

To choose to persist to the database, we need to create the corresponding table, which can be created in the Quartz official website Download, extract and find the SQL script of the corresponding database in the docs\dbTables directory.

For convenience, I also put the file in the project source resources.

To operate the database, we introduce related dependencies. If you have an ORM framework, such as mybatis, hibernate, or jpa, you don't need to introduce jdbc dependency.

<!--mysql Connect-->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

<!--druid Connection pool-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.10</version>
</dependency>

<!--jdbc rely on-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

In the application.yml configuration file, we declare the quartz persistence mode.

server:
  port: 10900

spring:
  profiles:
    active: dev
  quartz:
    job-store-type: jdbc #Persist to database
    properties:
      org:
        quartz:
          datasource:
            # The new driver is changed from com.mysql.jdbc.Driver to com.mysql.cj.jdbc.Driver
            driver-class-name: com.mysql.cj.jdbc.Driver
            # You must configure either the server or jdbc driver (via the server time zone configuration property) to use a more specific time zone value if you want to use 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 #Stdjdbc delegate description cluster support
            tablePrefix: QRTZ_
            isClustered: true
            clusterCheckinInterval: 1000
            useProperties: false
          threadPool:
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 20
            threadPriority: 5

Here is job store type: JDBC, which means persistent to database, and then data source. Since there is no other ORM data source for this demonstration project, the data source information is defined in the data source node under the quartz node. If it already exists, the same attribute can be used for configuration. Of course, the most important thing is the quartz data source declaration.

The key here is @ QuartzDataSource, which is different from the existing datasource in the project.

//Error:EmbeddedDatabaseType class not found, spring JDBC dependency is required for Druid data source initialization, which has been included in JPA or mybatis dependency.
@Bean
@QuartzDataSource
@ConfigurationProperties(prefix = "spring.quartz.properties.org.quartz.datasource")
DataSource quartzDataSource(){
    return DruidDataSourceBuilder.create().build();
}

In this way, persistence has been configured. We execute sql, and then start the project. After starting, we can see that our scheduled scheduling data already exists in the database.

Source address: https://github.com/imyanger/springboot-project/tree/master/p25-springboot-quartz

Topics: Java JDBC Spring Database MySQL