文章目录
- Java常用三类定时器快速入手指南
- 一、序言
- 二,Timer相关
- 1、概念
- 2、Timer类
- 3、TimerTask类
- 4、ScheduleExecutorService接口
- 三,Scheduled相关
- 1、配置
- 1.1 SpringMVC配置
- 1.2 SpringBoot配置
- (1)单线程
- (2)多线程
- 2、使用方法
- 2.1 cron表达式
- 2.2 其他参数
- 四,Quartz相关
- 1、概念
- 2、使用方法
- 2.1 导入依赖
- 2.2 实现功能
- 2.3 示例
- 3、进阶使用
- 3.1 存储数据
- (1)JobDataMap及jobDetail
- (2)私有属性
- 3.2 Job并发与持久化
- (1)并发
- (2)持久化
- 3.3 Trigger
- (1)通用属性
- (2)SimpleTrigger介绍
- (3)CronTrigger介绍
- 4、集群
- 4.1 步骤一
- 4.2 步骤二
- 4.3 步骤三
- 5、实例代码
- 5.1 实体entity
- 5.2 业务service
Java常用三类定时器快速入手指南
一、序言
小豪近来工作有遇到定时任务相关的需求,通常情况下,使用Spring
框架自带的Scheduled
注解就能满足大部分简单任务的需求,最近遇到的定时任务需求稍显复杂,Scheduled
已经有些力不从心了,遂考虑集成第三方定时任务框架Quartz
组件,完成业务需求。
本文小豪着重以代码案例的形式呈现,旨在帮助初学者快速入手Java定时器,掌握Java中常用三类定时任务的基本概念及用法。本文大纲如下:
二,Timer相关
1、概念
Timer
为java.util.Timer
工具类,java.util
包主要使用Timer
和TimerTask
这两个类:
Timer
直接从Object
继承,相当计时器,能够用它来指定某个时间来执行一项任务,或者每隔一定时间间隔反复执行同一个任务。创建一个Timer
后,就会生成一个线程在背后运行,来控制任务的执行。TimerTask
就是用来实现某项任务的类,它实现了Runnable
接口,因此相当于一个线程。
2、Timer类
(1)构造方法
// 创建一个新计时器
Timer()// 创建新计时器,可指定其相关的线程作为守护线程运行
Timer(boolean isDaemon)// 创建新计时器,设置指定名称
Timer(String name)// 创建新计时器,设置指定名称及是否守护线程
Timer(String name, boolean isDaemon)
(2)普通方法
// 安排在指定延迟后执行指定的任务
/* 参数:task - 所要安排的任务delay - 执行任务前的延迟时间,单位是毫秒
*/
void schedule(TimerTask task,long delay)
// 例:程序启动后3秒之后执行
Timer timer=new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("定时器执行。。。");}}, 3000);// 安排在指定的时间执行指定的任务。如果此时间已过去,则安排立即执行该任务(参数二:new Date() 代表立刻执行)
void schedule(TimerTask task,Date time)// 安排指定的任务从指定的延迟后开始进行重复的固定延迟执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
/* 参数:task - 所要安排的任务delay - 执行任务前的延迟时间,单位是毫秒period - 执行各后续任务之间的时间间隔,单位是毫秒
*/
void schedule(TimerTask task,long delay,long period)// 安排指定的任务在指定的时间开始进行重复的固定延迟执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
void schedule(TimerTask task,Date firstTime,long period)// 安排指定的任务在指定的延迟后开始进行重复的固定速率执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
void scheduleAtFixedRate(TimerTask task,long delay,long period)// 安排指定的任务在指定的时间开始进行重复的固定速率执行。以近似固定的时间间隔(由指定的周期分隔)进行后续执行
void scheduleAtFixedRate(TimerTask task,Date firstTime,long period)// 终止此计时器,丢弃所有当前已安排的任务
void cancel()// 从此计时器的任务队列中移除所有已取消的任务
int purge()
3、TimerTask类
(1)构造方法
// 创建新的计时器任务
TimerTask()
(2)普通方法
// 取消此计时器任务
boolean cancel()// 返回此任务最近实际执行的安排执行时间
long scheduledExecutionTime()// 此计时器任务要执行的操作(接口Runnable中的run)
void run()
4、ScheduleExecutorService接口
(1)概念
ScheduledExecutorService
线程池实现循环或延迟任务。
ScheduledExecutorService
和 Timer
的区别:
Timer
的内部只有一个线程,如果有多个任务的话就会顺序执行,会导致延迟时间和循环时间出现问题ScheduledExecutorService
是线程池,不会出现此问题,在对延迟任务和循环任务要求严格的时候,可使用ScheduledExecutorService
(2)使用方法
// 1.创建ScheduledExecutorService的实例(参数指定最大线程数量)
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(5);
// 2.调用方法
scheduledExecutorService.scheduleAtFixedRate(xxx...);
(3)普通方法
// 在给定的延迟之后创建并执行启用的一次性操作。
/*command - 命令要执行的任务delay - 从现在开始延迟执行的时间unit - 延迟参数的时间单位
*/
ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit);ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);// 在给定的初始延迟之后创建并执行启用的周期性操作
/*command - 命令要执行的任务initialDelay - 延迟第一次执行的时间period - 连续执行之间的时间间隔unit - initialDelay和period参数的时间单位
*/
ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit);// 在给定的初始延迟之后创建并执行先启用的周期性操作
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit);
三,Scheduled相关
1、配置
1.1 SpringMVC配置
<!--1.在xml里加入task的命名空间-->
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.1.xsd<!--2.启用注解驱动的定时任务-->
<task:annotation-driven scheduler="myScheduler"/><!--3.配置定时任务的线程池-->
<task:scheduler id="myScheduler" pool-size="5"/>
1.2 SpringBoot配置
(1)单线程
在启动类添加@EnableScheduling
注解即可
(2)多线程
@Configuration
@EnableScheduling
public class SchedulingConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.setScheduler(taskExecutor());}@Bean(destroyMethod="shutdown")public Executor taskExecutor() {return Executors.newScheduledThreadPool(5 ,new ThreadFactory() {private final AtomicLong counter = new AtomicLong();@Overridepublic Thread newThread(Runnable r) {Thread thread = new Thread(r);thread.setName("scheduler-" + counter.incrementAndGet());return thread;} });}
}
2、使用方法
@Scheduled
注解使用的方法必须是在@Component
注解下的类
2.1 cron表达式
<--在方法上使用@Scheduled,并配置对应参数即可-->
使用cron表达式的方法,在项目首次启动后不会直接运行,而是等到执行周期才会执行( 0/2 * * * * ? 表示每2秒执行任务)<--在线cron生成地址-->
https://www.bejson.com/othertools/cron/
2.2 其他参数
// 使用fixedRate/fixedDelay方式的定时器方法,在项目启动成功后会马上开始执行一次,再按照时间周期执行
// 例:@Scheduled(fixedDelay = 1000 * 5)fixedRate/fixedDelay区别:
fixedRate是配置上一次任务执行开始到下一次执行开始的间隔时间,不会等待上一次任务执行完成就会调度下一次任务,将其放入等待队列中
fixedDelay是配置的上一次任务执行结束到下一次执行开始的间隔时间,也就是说会等待上一次任务执行结束后,延迟间隔时间,再执行下一次任务
四,Quartz相关
1、概念
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,完全由Java开发,可以用来执行定时任务,类似于java.util.Timer
。相较Timer
, Quartz强大许多,具备分布式、持久性作业、调度任务管理能力。
Quartz的基本组成部分:
- 调度器:
Scheduler
- 任务:
JobDetail
- 触发器:
Trigger
,包括SimpleTrigger
和CronTrigger
2、使用方法
2.1 导入依赖
<!-- springboot -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
或者:
<!-- springmvc -->
<dependency> <groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId>
</dependency>
<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz-jobs</artifactId>
</dependency>
2.2 实现功能
(1)定义实现定时功能的接口,称之为Task
(或Job
)
(2)实现触发任务去执行的触发器,触发器Trigger
最基本的功能是指定Job
的执行时间,执行间隔,运行次数等
(3)使用Schedule
,将Job
和Trigger
两者结合起来,来负责功能的实现
2.3 示例
(1)新建一个能够打印任意内容的Job
public class PrintWordsJob implements Job {// 此类实现Job接口,复写execute()方法@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("定时器执行啦。。。"+new Date());}
}
(2)创建Schedule,执行任务
public class MyScheduler {public static void main(String[] args) throws SchedulerException {// 1.创建调度器SchedulerSchedulerFactory schedulerFactory = new StdSchedulerFactory();Scheduler scheduler = schedulerFactory.getScheduler();// 2.创建JobDetail实例,并与PrintWordsJob自定义类绑定(Job执行内容)JobDetail jobDetail = JobBuilder.newJob(PrintWordsJob.class).withIdentity("job1", "group1").build();// 3.构建Trigger实例,每隔3s执行一次// 使用SimpleScheduleBuilder或者CronScheduleBuilderTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1").startNow()//立即生效.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)//每隔3s执行一次.repeatForever()).build();//一直执行// 4.注册任务和定时器scheduler.scheduleJob(jobDetail, trigger);System.out.println("--------scheduler start! ------------");// 5.启动调度器scheduler.start();}}
3、进阶使用
3.1 存储数据
(1)JobDataMap及jobDetail
- JobDataMap:
Java Map
接口的一个实现,额外增加了一些便于存取基本类型的数据的方法,用于保存任务实例的状态信息 - jobDetail:包含
job
的各种属性设置,以及用于存储job
实例状态信息的JobDataMap
。
a.构建方式
//方式一:直接在构建JobDetail时,通过JobBuilder的usingJobData方法将数据放入JobDataMap中// 构建JobDetail实例
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("helloJob", "hello")//给job命名并分组.usingJobData("jobdd", "hello job")//通过JobBuilder的usingJobData方法给JobDataMap中存数据.build();
//方式二:构建JobDataMap,然后存入JobDetail中。或者从JobDetail中获取往里面put数据// 构建JobDetail实例
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("jobcc", "哈哈");
JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("helloJob", "hello")//给job命名并分组.usingJobData("jobdd", "hello job")//通过JobBuilder的usingJobData方法向JobDataMap中存数据.usingJobData(jobDataMap).build();
b.取数据方法
// 在job的执行过程中,可以从JobDataMap中取出数据// JobDetail的key由name和group组成
JobKey jobKey = jobExecutionContext.getJobDetail().getKey();
// Trigger的key由name和group组成
TriggerKey triggerKey = jobExecutionContext.getTrigger().getKey();
String bob = jobExecutionContext.getJobDetail().getJobDataMap().getString("jobdd");
String bob = jobExecutionContext.getJobDetail().getJobDataMap().getString("jobcc");
(2)私有属性
自定义私有属性,job
被实例化的时会自动调用其set
方法
public class HelloJob implements Job {//定义私有属性,会自动封装给jobprivate String jobcc;private String jobdd;private String jobaa;public void setJobcc(String jobcc) {this.jobcc = jobcc;}public void setJobdd(String jobdd) {this.jobdd = jobdd;}public void setJobaa(String jobaa) {this.jobaa = jobaa;}@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.err.println(context.getJobDetail().getKey());// JobDetail的key由name和group组成System.err.println(context.getTrigger().getKey());// Trigger的key由name和group组成System.err.println(jobcc);System.err.println(jobdd);System.err.println(jobaa);System.err.println("hello,quartz");}}
3.2 Job并发与持久化
仅在job
类上加入部分注解,即可实现Job
的并发与持久化。
(1)并发
@DisallowConcurrentExecution:将该注解加到job类上,告诉Quartz不要并发地执行同一个job定义(这里指特定的job类)的多个实例。
(2)持久化
@PersistJobDataAfterExecution:将该注解加在job类上,告诉Quartz在成功执行了job类的execute方法后(没有发生任何异常),更新JobDetail中JobDataMap的数据,使得该job(即JobDetail)在下一次执行的时候,JobDataMap中是更新后的数据,而不是更新前的旧数据。若使用@PersistJobDataAfterExecution注解,同时建议使用@DisallowConcurrentExecution注解
3.3 Trigger
Trigger是Quartz
框架中的核心接口,其最重要的两个实现类是CronTriggerImpl
与SimpleTriggerImpl
。
(1)通用属性
-
JobKey
:表示与该Trigger
绑定的Job
实例的标识,触发器被触发时,该指定的Job
实例会被执行 -
StartTime
:表示触发器的时间表首次被触发的时间,Java.util.Date
类型 -
EndTime
:指定触发器不再被触发的时间,Java.util.Date
类型
(2)SimpleTrigger介绍
在一个指定时间段内执行一次作业任务或是在指定的时间间隔内多次执行作业任务
// 实例:距离当前时间4秒钟之后首次执行任务,6秒后停止,每隔2秒执行,执行3次
// 创建一个SimpleTrigger实例,定义该Job4秒后执行,并且每隔两秒钟重复执行一次,6秒后停止
SimpleTrigger trigger=(SimpleTrigger)TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1")//定义name和group.startAt(date)//设置开始时间.endAt(endDate)//设置结束时间 .withSchedule(SimpleScheduleBuilder.simpleSchedule() //使用SimpleTrigger .withIntervalInSeconds(2)//每隔两秒执行一次 .withRepeatCount(3))//重复执行三次 .build();
(3)CronTrigger介绍
基于日历的作业调度器,而不是像SimpleTrigger
那样精确指定间隔时间,SimpleTrigger
能够实现的,CronTrigger
都能够实现,基本普遍都用CronTrigger
// 创建一个CronTrigger实例
CronTrigger trigger=(CronTrigger)TriggerBuilder.newTrigger().withIdentity("myTrigger", "group1")//定义name/group.withSchedule(CronScheduleBuilder.cronSchedule("0 5 21 * * ? *"))//填写cron表达式.build();
4、集群
4.1 步骤一
(1)下载quartz表
http://www.quartz-scheduler.org/downloads/
(2)表功能说明
(3)导入配置文件(quartz.properties)
# 配置JobStore,JobDataMaps是否都为String类型,默认false
org.quartz.jobStore.useProperties=false# 表的前缀,默认QRTZ_
org.quartz.jobStore.tablePrefix = QRTZ_# 是否加入集群
org.quartz.jobStore.isClustered = true# 调度实例失效的检查时间间隔 ms
org.quartz.jobStore.clusterCheckinInterval = 5000# 当设置为“true”时,此属性告诉Quartz 在非托管JDBC连接上调用setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED)。
org.quartz.jobStore.txIsolationLevelReadCommitted = true# 数据保存方式为数据库持久化
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX# 数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate# Scheduler 调度器属性配置
# 调度标识名 集群中每一个实例都必须使用相同的名称
org.quartz.scheduler.instanceName = ClusterQuartz
# ID设置为自动获取 每一个必须不同
org.quartz.scheduler.instanceId= AUTO# 配置ThreadPool
# 线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool# 指定线程数,一般设置为1-100直接的整数,根据系统资源配置
org.quartz.threadPool.threadCount = 10# 设置线程的优先级(可以是Thread.MIN_PRIORITY(即1)和Thread.MAX_PRIORITY(这是10)之间的任何int 。默认值为Thread.NORM_PRIORITY(5)。)
org.quartz.threadPool.threadPriority = 5
(4)配置数据源
spring.datasource.url=jdbc:mysql://localhost:3306/xiaohao?characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.max-active=1000
spring.datasource.max-idle=20
spring.datasource.min-idle=5
spring.datasource.initial-size=10
4.2 步骤二
(1)QuartzConfigure配置类
@Configuration
public class SchedulerConfig {/*** 配置文件路径*/private static final String QUARTZ_CONFIG = "/quartz.properties";/*** 注入数据源*/@Autowiredprivate DataSource dataSource;/*** 通过SchedulerFactoryBean获取Scheduler的实例*/@Beanpublic Scheduler scheduler() throws IOException {return schedulerFactoryBean().getScheduler();}/*** 配置SchedulerFactory*/@Beanpublic SchedulerFactoryBean schedulerFactoryBean() throws IOException {SchedulerFactoryBean factory = new SchedulerFactoryBean();factory.setSchedulerName("cluster_scheduler");factory.setDataSource(dataSource);//将spring上下文放入quartz中, 用于在job执行时获取注入beanfactory.setApplicationContextSchedulerContextKey("application");factory.setQuartzProperties(quartzProperties());factory.setTaskExecutor(schedulerThreadPool());//延时3秒启动factory.setStartupDelay(3);return factory;}/*** 从quartz.properties文件中读取Quartz配置属性*/@Beanpublic Properties quartzProperties() throws IOException {PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_CONFIG));propertiesFactoryBean.afterPropertiesSet();return propertiesFactoryBean.getObject();}/*** 自定义线程池*/@Beanpublic Executor schedulerThreadPool(){ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(Runtime.getRuntime().availableProcessors());executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors());executor.setQueueCapacity(Runtime.getRuntime().availableProcessors());return executor;}
}
(2)QuartzJob定时任务类
// QuartzJobBean抽象类默认实现Job接口,并对工厂进行了一些自动化配置
// 及时更新JobDetail中JobDataMap的数据
@PersistJobDataAfterExecution
// 标记于实现Job的类上,代表不允许并发执行
@DisallowConcurrentExecution
public class QuartzJob extends QuartzJobBean {/*** Quartz Job真正的执行逻辑*/@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {try {System.out.println(context.getScheduler().getSchedulerInstanceId());System.out.println("定时器执行啦。。。");} catch (Exception e) {e.printStackTrace();}}
}
4.3 步骤三
(1)定义任务
@Controller
public class MyTask {@Autowiredprivate Scheduler scheduler;@RequestMapping("/setScheduler")@ResponseBodypublic String setScheduler() throws SchedulerException {// 1.创建JobDetail实例,并与QuartzJob自定义类绑定(Job执行内容)JobDetail jobDetail = JobBuilder.newJob(QuartzJob.class).withIdentity("job1", "group1").build();// 2.构建Trigger实例,每隔3s执行一次// 使用SimpleScheduleBuilder或者CronScheduleBuilderTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "triggerGroup1").startNow()//立即生效.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)//每隔3s执行一次.repeatForever()).build();//一直执行// 3.注册任务和定时器,交给scheduler调度scheduler.scheduleJob(jobDetail, trigger);return "hello,quartz";}
}
5、实例代码
5.1 实体entity
@Data
public class JobAndTrigger {/*** 任务名称(*)*/private String jobName;/*** 任务所在组(*)*/private String jobGroup;/*** 任务类名(*)* 例:"com.example.demo.task.QuartzJob"*/private String jobClassName;/*** 触发器名称*/private String triggerName;/*** 触发器所在组*/private String triggerGroup;/*** cron表达式(*)*/private String cronExpression;/*** 时区*/private String timeZoneId;/*** 任务描述(*)*/private String description;/*** 状态*/private String triggerState;
}
5.2 业务service
@Service
@Slf4j
public class JobService {@Autowiredprivate Scheduler scheduler;/*** 添加一个定时任务** @param jobAndTrigger*/public void addCronJob(JobAndTrigger jobAndTrigger) throws SchedulerException {try {JobKey jobKey = JobKey.jobKey(jobAndTrigger.getJobName(), jobAndTrigger.getJobGroup());JobDetail jobDetail = scheduler.getJobDetail(jobKey);if (jobDetail != null) {log.error("job:" + jobAndTrigger.getJobName() + " 已存在");} else {// 创建JobDetail实例,并与QuartzJob自定义类绑定(Job执行内容)jobDetail = JobBuilder.newJob((Class<Job>) Class.forName(jobAndTrigger.getJobClassName())).withIdentity(jobAndTrigger.getJobName(), jobAndTrigger.getJobGroup()).withDescription(jobAndTrigger.getDescription()).build();// 用JopDataMap来传递数据jobDetail.getJobDataMap().put("taskData", "定时任务传递数据");// 表达式调度构建器,首先校验表达式格式if (!CronExpression.isValidExpression(jobAndTrigger.getCronExpression())) {log.error("cron表达式规则不正确");}CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(jobAndTrigger.getCronExpression());// 根据cronExpression表达式构建新的triggerTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobAndTrigger.getJobName() + "_trigger", jobAndTrigger.getJobGroup() + "_trigger").withSchedule(cron).withDescription(jobAndTrigger.getDescription()).build();// 注册任务和定时器,交给scheduler调度scheduler.scheduleJob(jobDetail, trigger);}} catch (Exception e) {log.error("任务创建失败:", e);}}/*** 暂停任务** @param jobName* @param jobGroup*/public void pauseJob(String jobName, String jobGroup) throws SchedulerException {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup + "_trigger");scheduler.pauseTrigger(triggerKey);} catch (SchedulerException e) {log.error("定时任务暂停失败:", e);}}/*** 恢复任务** @param jobName* @param jobGroup*/public void resumeJob(String jobName, String jobGroup) throws SchedulerException {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName + "_trigger", jobGroup + "_trigger");scheduler.resumeTrigger(triggerKey);} catch (SchedulerException e) {log.error("定时任务恢复失败:", e);}}/*** 修改任务表达式并重新调度** @param jobAndTrigger*/public void rescheduleJob(JobAndTrigger jobAndTrigger) throws SchedulerException {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobAndTrigger.getJobName() + "_trigger", jobAndTrigger.getJobGroup() + "_trigger");// 表达式调度构建器CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(jobAndTrigger.getCronExpression());CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);String oldCron = trigger.getCronExpression();if (oldCron.isEmpty() || !oldCron.equals(jobAndTrigger.getCronExpression())) {// 表达式调度构建器,首先校验表达式格式if (!CronExpression.isValidExpression(jobAndTrigger.getCronExpression())) {log.error("cron表达式规则不正确");}// 按新的cronExpression表达式重新构建triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(cron).build();// 按新的trigger重新设置job执行scheduler.rescheduleJob(triggerKey, trigger);}} catch (SchedulerException e) {log.error("定时任务修改失败:", e);}}/*** 删除job** @param jobName* @param jobGroup*/public void deleteJob(String jobName, String jobGroup) throws SchedulerException {try {JobKey jobKey = JobKey.jobKey(jobName, jobGroup);scheduler.deleteJob(jobKey);} catch (SchedulerException e) {log.error("定时任务删除失败:", e);}}}