SpringBoot 定时任务

2023-05-11 23:02 阅读

SpringBoot提供了非常方便使用的定时任务功能。同时也支持Quartz

开启任务调度器

@Configuration
@EnableScheduling
public class SchedulerConfig {
}

使用定时任务

// 每5秒执行一次
@Scheduled(fixedDelay = 5000)
public void doSomething() {
    // something that should run periodically
}

// cron表达式
@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {
    // something that should run on weekdays only
}

Quartz使用

pom.xml中加入以下代码:

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

自动装配器SchedulerFactoryBean会提供Scheduler对象以供使用。

相关配置:

# 集群环境需要使用jdbc。默认:memory
#spring.quartz.job-store-type: jdbc
# quartz是否集群
#spring.quartz.properties.org.quartz.jobStore.isClustered: true
# jdbc模式需要指定驱动委托类。官方文档:https://www.quartz-scheduler.org/documentation/quartz-2.3.0/configuration/ConfigJobStoreTX.html
#spring.quartz.properties.org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#spring.quartz.properties.org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
#spring.quartz.properties.org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
#spring.quartz.properties.org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.MSSQLDelegate
#spring.quartz.properties.org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.SybaseDelegate
#spring.quartz.properties.org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.HSQLDBDelegate
# 通过Spring配置生成的Job,是否覆盖持久化到数据库的Job。需要设置成true。默认:false
spring.quartz.overwrite-existing-jobs: true
# 使用liquibase初始化数据库,要使用 never。默认:embedded
spring.quartz.jdbc.initialize-schema: never

创建数据库

通常使用Quartz都是因为需要支持集群,集群则需要创建数据库表。

可以手动创建创建表结构,SQL脚本在quartz的jar包中org/quartz/impl/jdbcjobstore/目录下,可以根据数据库类型选择相应的脚本。

如果系统中使用了liquibase,则简单很多,直接包含org/quartz/impl/jdbcjobstore/liquibase.quartz.init.xml文件即可。

databaseChangeLog:
  - include:
      file: org/quartz/impl/jdbcjobstore/liquibase.quartz.init.xml

使用JobDetailFactoryBean创建JobDetail

example.ExampleJob需要继承QuartzJobBean

package example;

@Component
public class ExampleJob extends QuartzJobBean {
    // fields ...
    private MyService myService;

    // 支持注入Spring托管对象
    // Inject "MyService" bean
    @Autowired
    public void setMyService(MyService myService) {
        this.myService = myService;
    }

    private int timeout;

    /**
     * Setter called after the ExampleJob is instantiated
     * with the value from the JobDetailFactoryBean (5)
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
        // do the actual work
    }
}

xml配置文件:

<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="example.ExampleJob"/>
    <property name="jobDataAsMap">
        <map>
            <entry key="timeout" value="5"/>
        </map>
    </property>
    <!-- 没有绑定触发器时,必须设置持久性为 true -->
    <property name="durability" value="true"/>
</bean>

java配置类(可代替xml配置文件):

    @Bean
    public JobDetailFactoryBean createExampleJob() {
        final JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean();
        jobDetailFactory.setJobClass(ExampleJob.class);
        JobDataMap dataMap = new JobDataMap();
        dataMap.put("timeout", 5);
        jobDetailFactory.setJobDataMap(dataMap);
        // 没有绑定触发器时,必须设置持久性为 true
        jobDetailFactory.setDurability(true);
        return jobDetailFactory;
    }

使用MethodInvokingJobDetailFactoryBean创建JobDetail

如果只是想简单的执行某一个方法,不想继承QuartzJobBean,可以使用这种方式。但这种方式不支持Quartz jdbc模式(集群需要开启jdbc模式):

@Component("exampleBusinessObject")
public class ExampleBusinessObject {
    public void doIt() {
        // do the actual work
    }
}

xml配置文件:

<bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <property name="targetObject" ref="exampleBusinessObject"/>
    <property name="targetMethod" value="doIt"/>
</bean>

java配置类(可代替xml配置文件):

    @Bean
    public MethodInvokingJobDetailFactoryBean createBusinessJob(ExampleBusinessObject exampleBusinessObject) {
        final MethodInvokingJobDetailFactoryBean jobDetailFactory = new MethodInvokingJobDetailFactoryBean();
        jobDetailFactory.setTargetObject(exampleBusinessObject);
        jobDetailFactory.setTargetMethod("doIt");
        return jobDetailFactory;
    }

创建 Trigger

xml 配置:

<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
    <!-- see the example of method invoking job above -->
    <property name="jobDetail" ref="jobDetail"/>
    <!-- 10 seconds -->
    <property name="startDelay" value="10000"/>
    <!-- repeat every 50 seconds -->
    <property name="repeatInterval" value="50000"/>
</bean>

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
    <property name="jobDetail" ref="exampleJob"/>
    <!-- run every morning at 6 AM -->
    <property name="cronExpression" value="0 0 6 * * ?"/>
</bean>

java配置类(可代替xml配置文件):

和之前类似,代码略...

设置SchedulerFactoryBean

SpringBoot环境下不需要这一步。SpringBoot会自动创建SchedulerFactoryBean,并把Trigger加入其中。

如果没有使用SpringBoot,直接使用Spring,则需要手动配置。为了更好理解SchedulerFactoryBean的工作原理,这里列出了Spring环境下相应的代码:

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
    <property name="triggers">
        <list>
            <ref bean="cronTrigger"/>
            <ref bean="simpleTrigger"/>
        </list>
    </property>
</bean>

Quartz Scheduler 和 Spring Scheduler 的区别

Spring Scheduler是非常轻量级的任务调度器,如果你只需要做一些简单的定时任务,直接使用它就好了。

Quartz Scheduler提供了很多高级功能,最主要的就是支持集群。如果需要做集群,就选择它。

参考资料

咨询
交流群
电话