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