当前位置: 首页 > 工具软件 > Quartz EX > 使用案例 >

Springboot集成Quartz定时任务yml文件配置方式

陆展
2023-12-01

构建maven项目,引入maven依赖包

其中quartz、quartz-jobs、spring-boot-starter-quartz、spring-context-support  四个依赖包为quartz定时任务所需

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>cronjob</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>cronjob</name>
    <description>cronjob project for Spring Boot</description>
    <!--自定义属性值 一般自定义依赖包的版本号与指定项目字符编码-->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <spring-cloud.version>Hoxton.SR3</spring-cloud.version>
        <spring-cloud-alibaba.version>2.2.1.RELEASE</spring-cloud-alibaba.version>
        <quartz.version>2.3.2</quartz.version>
    </properties>
    <dependencies>
        <!--引入其他服务的api模块-->
        <dependency>
            <groupId>com.springcloud</groupId>
            <artifactId>dubbo_api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>${quartz.version}</version>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>${quartz.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>
    <!--管理spring-cloud-alibaba相关依赖包的版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

quartz的核心job的创建是由Quartz通过反射创建的,并未交由Spring容器创建。故原则上来说,是无法在Job实例中使用依赖注入

package com.example.cronjob.config;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

/**
 * @author Administrator
 * @description Job的创建是由Quartz通过反射创建的
 * 并未交由Spring容器创建。故原则上来说,是无法在Job实例中使用依赖注入
 * @date 2021-03-22 10:54
 */
@Component
@EnableScheduling
public class JobFactory extends AdaptableJobFactory {

    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        // 使用AutowireCapableBeanFactory完成对IOC外Bean的注入操作
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }
}

调度器Scheduler的创建,用于对定时任务的各项操作

package com.example.cronjob.config;

import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

import java.io.IOException;

/**
 * @author Administrator
 * @description
 * @date 2021-03-22 10:54
 */
@Configuration
public class QuartzConfig {

    @Autowired
    private JobFactory jobFactory;

    @Bean(name = "schedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        // 设置自行启动
        //schedulerFactoryBean.setAutoStartup(false);
        schedulerFactoryBean.setJobFactory(jobFactory);
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        // 延时启动
        schedulerFactoryBean.setStartupDelay(1);
        return schedulerFactoryBean;
    }

    @Bean(name = "scheduler")
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }
}

对应yml配置的实体类,用于匹配配置文件信息做定时任务启动

package com.example.cronjob.entity;

import lombok.Data;

import java.io.Serializable;

/**
 * @author Administrator
 * @description
 * @date 2021-03-22 14:01
 */
@Data
public class JobEntity implements Serializable {
    private static final long serialVersionUID = 6602540505183675348L;

    private String jobName;
    private String jobGroup;
    private String jobClassName;
    private String cronExpression;
    private int triggerState;
    private int sort;
}

创建一个枚举类判断任务状态

package com.example.cronjob.common;

/**
 * @author Administrator
 * @description
 * @date 2021-03-22 14:34
 */
public enum QuartzEnum {

    NORMAL(1, "正常"),
    PAUSED(0, "暂停");
    private int code;
    private String name;

    QuartzEnum(int code, String name) {
        this.code = code;
        this.name = name;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

使用预加载方式,在项目启动成功之后读取quartz.yml配置文件信息,并且把定时任务加入调度器管理

package com.example.cronjob.config;

import com.example.cronjob.common.QuartzEnum;
import com.example.cronjob.entity.JobEntity;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author Administrator
 * @description
 * @date 2021-03-22 14:15
 */
@Component
@ConfigurationProperties(prefix = "quartz")
public class ScheduleJobListenerStart implements ApplicationRunner {

    @Autowired
    @Qualifier("scheduler")
    private Scheduler scheduler;

    List<JobEntity> jobs = new ArrayList<>();

    @Override
    public void run(ApplicationArguments args) throws Exception {
        for(JobEntity entity : jobs) {
            // 当定时任务状态为0时,不启动
            if (entity.getTriggerState() == QuartzEnum.PAUSED.getCode()) {
                continue;
            }
            // 创建jobDetail实例,绑定Job实现类
            // 指明job的名称,所在组的名称,以及绑定job类
            Class<? extends Job> jobClass = (Class<? extends Job>) (Class.forName(entity.getJobClassName())
                    .newInstance().getClass());
            JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(entity.getJobName(), entity.getJobGroup()).build();
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(entity.getCronExpression());
            CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(entity.getJobName(), entity.getJobGroup())
                    .withSchedule(scheduleBuilder).build();
            Map<String, Object> map = new HashMap<>();
            map.put("sort", entity.getSort());
            if (map != null) {
                trigger.getJobDataMap().putAll(map);
            }
            scheduler.scheduleJob(jobDetail, trigger);
        }
    }

    public List<JobEntity> getJobs() {
        return jobs;
    }

    public void setJobs(List<JobEntity> jobs) {
        this.jobs = jobs;
    }
}

项目application.yml配置文件信息

spring:
  profiles:
    active: test
    include: quartz
  application:
    name: cron-job

本地测试application-test.yml配置文件

server:
  port: 8085
dubbo:
  protocol:
    name: dubbo
    port: -1
  registry:
    address: spring-cloud://192.168.3.192
    check: false
  cloud:
    # 订阅服务提供者, 要订阅多个服务,请使用,(英文逗号)作为分隔符
    subscribed-services: dubbo-provider
    # 解决Dubbo中生产者未启动, 使用@Reference实例化的对象都是null
    # 消费者启动报错的问题, 很多时候服务是提供者也是消费者
    # 启动时检查提供者是否存在,true报错,false忽略  默认值true
    check: false
    # 远程服务调用超时时间(毫秒), 默认值1000
    timeout: 20000
spring:
  # 是否开启AOP面向切面
  aop:
    auto: true
  cloud:
    nacos:
      discovery:
        # nacos集群方式就是把所有数据持久化到mysql数据库
        # 多个注册中心配置ip1:port1,ip2:port2,ip3:port3
        server-addr: 192.168.3.192:8848
org:
  quartz:
    threadPool:
      class: org.quartz.simpl.SimpleThreadPool
      threadCount: 100
      threadPriority: 5
      threadsInheritContextClassLoaderOfInitializingThread: true

quartz定时任务列表application-quartz.yml配置文件

quartz:
  # jobGroup名称一致的情况下,不可出现相同jobName
  jobs[0]:
    jobName: 本地定时任务
    # 以服务名为组名
    jobGroup: localhost
    # 业务逻辑处理类的包名
    jobClassName: com.example.cronjob.task.LocalhostTask
    # cron表达式 每30秒执行一次
    cronExpression: 0/30 * * * * ?
    # 任务状态 1 正常 0 暂停
    triggerState: 1
    # 排序
    sort: 1
  jobs[1]:
    jobName: 用户服务-同步员工信息
    # 以服务名为组名
    jobGroup: dubbo-provider
    # 业务逻辑处理类的包名
    jobClassName: com.example.cronjob.task.UserSyncTask
    # cron表达式 每5分钟执行一次
    cronExpression: 0 0/5 * * * ? *
    # 任务状态 1 正常 0 暂停
    triggerState: 1
    sort: 2

测试本地设置一个定时任务每30秒执行一次

package com.example.cronjob.task;

import org.quartz.*;

import java.io.Serializable;

/**
 * @author Administrator
 * @description
 * @date 2021-03-22 16:26
 */
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class LocalhostTask implements Job, Serializable {

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("=========本地执行定时任务=========");
    }
}

调用其他微服务,每5分钟执行一次

package com.example.cronjob.task;

import com.springcloud.dubbo_api.service.HelloServiceApi;
import org.apache.dubbo.config.annotation.Reference;
import org.quartz.*;

import java.io.Serializable;
import java.util.Date;

/**
 * @author Administrator
 * @description
 * @date 2021-03-22 14:57
 */
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class UserSyncTask implements Job, Serializable {

    @Reference
    private HelloServiceApi helloServiceApi;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("=========同步员工信息=========" + new Date());
        try {
            helloServiceApi.hello("cron_job");
        } catch (Exception e) {
            JobExecutionException ex = new JobExecutionException(e);
            // true 表示立即重新执行该任务, 不断重试,直到成功,项目中不能确定其他服务中断的时间有多长,不建议设置该参数
            // 微服务中,比如当前为A服务,调用B服务的接口,而B服务中断重启,当B服务重启成功并且调用接口成功后退出该异常循环,类似心跳机制
            //ex.setRefireImmediately(true);
            // true 表示 Quartz 会自动取消所有与这个 job 有关的 trigger,从而避免再次运行 job
            // 当某个服务中断或重启时,手动恢复指定的任务
            // 也可以单独设定一个定时任务获取已停止的任务进行恢复
            ex.setUnscheduleAllTriggers(true);
            throw ex;
        }
    }
}

如果需要对定时任务的暂停、恢复等操作,查看另一个文章

https://blog.csdn.net/m0_37845840/article/details/114934611?spm=1001.2014.3001.5501

 类似资料: