签入版本

This commit is contained in:
2026-09-10 21:41:50 +08:00
commit 717116a605
2693 changed files with 355025 additions and 0 deletions
@@ -0,0 +1,272 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.scheduler.utils;
import cn.hutool.extra.spring.SpringUtil;
import com.xiaomayi.core.utils.StringUtils;
import com.xiaomayi.scheduler.model.ScheduleJob;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
/**
* <p>
* 定时任务调度执行工具类
* 提供定时任务方法的动态调用功能,支持从Spring容器获取Bean或直接实例化类来执行目标方法
* </p>
*
* @author 小蚂蚁云团队
* @since 2024-06-13
*/
public class JobExecuteUtils {
/**
* 执行定时任务方法
* 根据任务配置的目标字符串动态调用相应的方法
* 支持格式:beanName.methodName(参数1,参数2,...) 或 className.methodName(参数1,参数2,...)
*
* @param scheduleJob 定时任务对象,包含任务执行的目标信息
* @throws Exception 当方法调用过程中发生异常时抛出,包括反射异常、实例化异常等
*/
public static void invokeMethod(ScheduleJob scheduleJob) throws Exception {
// 获取任务执行目标字符串,格式如:userService.getUserList('admin', 123) 或 com.example.UserService.getUserList('admin', 123)
String invokeTarget = scheduleJob.getUrl();
// 解析目标字符串获取Bean/类名
String beanName = getBeanName(invokeTarget);
// 解析目标字符串获取方法名
String methodName = getMethodName(invokeTarget);
// 解析目标字符串获取方法参数列表
List<Object[]> methodParams = getMethodParams(invokeTarget);
// 判断目标是Spring Bean还是完整的类名
if (!isValidClassName(beanName)) {
// 从Spring容器中获取Bean实例
Object bean = SpringUtil.getBean(beanName);
// 调用目标方法
invokeMethod(bean, methodName, methodParams);
} else {
// 通过反射实例化类对象
Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
// 调用目标方法
invokeMethod(bean, methodName, methodParams);
}
}
/**
* 通过反射调用目标对象的方法
*
* @param bean 目标对象实例
* @param methodName 要调用的方法名称
* @param methodParams 方法参数列表,每个Object[]包含参数值和参数类型
* @throws NoSuchMethodException 当找不到指定方法时抛出
* @throws SecurityException 当安全管理器拒绝访问时抛出
* @throws IllegalAccessException 当方法访问权限不足时抛出
* @throws IllegalArgumentException 当参数不匹配时抛出
* @throws InvocationTargetException 当被调用方法本身抛出异常时抛出
*/
private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) {
// 有参数的方法调用:获取参数类型数组,通过反射获取方法对象,传入参数值调用方法
Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
method.invoke(bean, getMethodParamsValue(methodParams));
} else {
// 无参数的方法调用:直接获取无参方法并调用
Method method = bean.getClass().getMethod(methodName);
method.invoke(bean);
}
}
/**
* 校验字符串是否为有效的类全限定名
* 判断标准:包含多于一个点号(.)视为类名,否则视为Spring Bean名称
*
* @param invokeTarget 待校验的字符串
* @return true-是类名,false-是Bean名
*/
public static boolean isValidClassName(String invokeTarget) {
return StringUtils.countMatches(invokeTarget, ".") > 1;
}
/**
* 从目标字符串中解析出Bean名称或类名
* 目标字符串格式:beanName.methodName(参数) 或 className.methodName(参数)
*
* @param invokeTarget 目标字符串
* @return Bean名称或类全限定名
*/
public static String getBeanName(String invokeTarget) {
// 先截取括号前的部分:beanName.methodName
String beanName = StringUtils.substringBefore(invokeTarget, "(");
// 再截取最后一个点号前的部分:beanName
return StringUtils.substringBeforeLast(beanName, ".");
}
/**
* 从目标字符串中解析出方法名称
* 目标字符串格式:beanName.methodName(参数) 或 className.methodName(参数)
*
* @param invokeTarget 目标字符串
* @return 方法名称
*/
public static String getMethodName(String invokeTarget) {
// 先截取括号前的部分:beanName.methodName
String methodName = StringUtils.substringBefore(invokeTarget, "(");
// 再截取最后一个点号后的部分:methodName
return StringUtils.substringAfterLast(methodName, ".");
}
/**
* 从目标字符串中解析方法参数列表
* 支持解析字符串、布尔值、长整型、双精度浮点型和整型参数
* 参数格式示例:('字符串参数', true, 123L, 45.67D, 89)
*
* @param invokeTarget 目标字符串
* @return 参数列表,每个Object[]包含两个元素:[参数值, 参数类型Class]
* 返回null表示无参数
*/
public static List<Object[]> getMethodParams(String invokeTarget) {
// 提取括号内的参数部分
String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
if (StringUtils.isEmpty(methodStr)) {
return null;
}
// 使用正则表达式分割参数,考虑字符串中包含逗号的情况
// (?=([^"']*["'][^"']*["'])*[^"']*$) 确保不分割引号内的逗号
String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
List<Object[]> classs = new LinkedList<>();
for (int i = 0; i < methodParams.length; i++) {
String str = StringUtils.trimToEmpty(methodParams[i]);
// 字符串类型:以单引号或双引号开头
if (StringUtils.startsWithAny(str, "'", "\"")) {
classs.add(new Object[]{StringUtils.substring(str, 1, str.length() - 1), String.class});
}
// 布尔类型:值为true或false(不区分大小写)
else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) {
classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});
}
// 长整型:以L结尾
else if (StringUtils.endsWith(str, "L")) {
classs.add(new Object[]{Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class});
}
// 双精度浮点型:以D结尾
else if (StringUtils.endsWith(str, "D")) {
classs.add(new Object[]{Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class});
}
// 默认处理为整型
else {
classs.add(new Object[]{Integer.valueOf(str), Integer.class});
}
}
return classs;
}
/**
* 从参数列表中提取参数类型数组
*
* @param methodParams 参数列表,每个Object[]格式为[参数值, 参数类型Class]
* @return 参数类型Class数组
*/
public static Class<?>[] getMethodParamsType(List<Object[]> methodParams) {
Class<?>[] classs = new Class<?>[methodParams.size()];
int index = 0;
for (Object[] os : methodParams) {
classs[index] = (Class<?>) os[1];
index++;
}
return classs;
}
/**
* 从参数列表中提取参数值数组
*
* @param methodParams 参数列表,每个Object[]格式为[参数值, 参数类型Class]
* @return 参数值数组
*/
public static Object[] getMethodParamsValue(List<Object[]> methodParams) {
Object[] classs = new Object[methodParams.size()];
int index = 0;
for (Object[] os : methodParams) {
classs[index] = (Object) os[0];
index++;
}
return classs;
}
}
@@ -0,0 +1,376 @@
// +======================================================================
// | 小蚂蚁云·企业数字化开发平台 [ 加速数字化转型,构建智能未来 ]
// +----------------------------------------------------------------------
// | 核心价值:赋能开发者 · 服务企业 · 共建生态
// +----------------------------------------------------------------------
// | Copyright (c) 2020-2026 小蚂蚁云团队 版权所有
// +----------------------------------------------------------------------
// | 官方平台: https://www.xiaomayicloud.com
// +======================================================================
// | 【知识产权声明】
// | 1. 权属声明:本软件是受《中华人民共和国著作权法》
// | 保护的专有财产,完整版权归小蚂蚁云团队所有
// | 2. 权利范围:所有知识产权(商标、专利、著作权、
// | 商业秘密等)均归小蚂蚁云团队所有,受法律保护
// | 3. 授权性质:用户仅可获得有限的、非独占的使用许可
// | 4. 禁止行为:未经书面授权,禁止对本软件本身
// | 申请任何知识产权
// | 5. 权利保留:未在本协议中明示授予的一切权利
// | 均由小蚂蚁云团队保留
// +======================================================================
// | 【授权状态说明】
// | 1. 未授权状态:用户未购买有效的商业许可证
// | 2. 商业授权:已购买正式商业许可证的用户
// +======================================================================
// | 【绝对禁止条款】
// | 无论授权状态如何,任何用户均严格禁止以下行为:
// | 1. 逆向工程:对软件进行反编译、反汇编、技术破解或任何形式的逆向分析
// | 2. 版权破坏:移除、修改、遮挡软件中的版权标识、许可控制或技术保护措施
// | 3. 非法传播:复制、分发、出租、出借、转售、再许可本软件或其许可权利
// | 4. 竞争性使用:利用本软件的代码、架构、设计开发直接竞争的产品或服务
// | 5. 侵权使用:将软件用于侵犯第三方知识产权或其他合法权益的用途
// +======================================================================
// | 【商业授权许可范围】
// | 购买有效商业许可证的用户,在遵守上述禁止条款的前提下,获得:
// | 1. 使用权利:在许可证约定的项目数量、开发者数量范围内使用本软件
// | 2. 技术支持:商业授权用户可以获取本地开发部署的技术支持服务
// | 3. 版本更新:在许可证有效期内获取软件更新、安全补丁和功能增强
// | 4. 商业部署:将基于本软件开发的应用程序用于商业运营和生产环境
// +======================================================================
// | 【许可证获取】
// | 1. 获取途径:仅通过小蚂蚁云官方渠道购买(官网、授权代理商),购买记录凭证
// | 2. 转让限制:许可证与购买主体绑定,未经书面同意不得转让
// | 3. 终止情形:许可证到期、违反协议、破产清算等情况下自动终止
// +======================================================================
// | 【合法使用要求】
// | 1. 仅限用于合法合规的软件研发
// | 2. 严禁用于任何违法、侵权或恶意行为
// | 3. 严禁违反我国法律法规和政策
// +======================================================================
// | 【免责声明】
// | 因使用本框架导致的以下情况,我们概不负责:
// | 1. 项目研发中的意外、疏忽、违约等风险
// | 2. 侵犯第三方知识产权或其他合法权益
// | 3. 任何直接、间接、附带或衍生一切损失
// | 4. 用户违规违法行为的一切法律后果
// +======================================================================
// | 【协议重要提示】
// | 1. 本声明是《小蚂蚁云最终用户许可协议》的摘要版本
// | 2. 下载、安装或使用本软件即表示您接受全部协议条款
// | 3. 我们保留单方面修改本声明的权利,修改后的版本在官网公布即生效
// | 4. 用户有义务定期查看最新版本,继续使用视为接受修改
// +======================================================================
// | 【侵权举报与合规】
// | 1. 知识产权侵权举报:请联系官方客服
// | 2. 许可证合规咨询:xiaomayicloud@163.com
// | 3. 违规使用将终止授权并追究责任
// | 4. 无条件配合司法机关调查取证
// | 5. 保留一切法律追诉权利
// | 6. 对有效举报和合规建议,我们将给予感谢和奖励
// +======================================================================
package com.xiaomayi.scheduler.utils;
import com.xiaomayi.scheduler.constant.ScheduleConstant;
import com.xiaomayi.scheduler.exception.ScheduleException;
import com.xiaomayi.scheduler.factory.AsyncJobFactory;
import com.xiaomayi.scheduler.factory.SyncJobFactory;
import com.xiaomayi.scheduler.model.ScheduleJob;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
/**
* <p>
* 定时任务调度工具类
* 提供Quartz定时任务的创建、更新、删除、暂停、恢复等操作工具方法
* </p>
*
* @author 小蚂蚁云团队
* @since 2024-06-13
*/
@Slf4j
public class ScheduleUtils {
/**
* 获取触发器KEY
* 触发器命名规则:TASK_CLASS_NAME + jobId
*
* @param jobId 任务ID
* @param jobGroup 任务分组
* @return TriggerKey 触发器键
*/
public static TriggerKey getTriggerKey(Integer jobId, String jobGroup) {
String triggerName = ScheduleConstant.TASK_CLASS_NAME + jobId;
return TriggerKey.triggerKey(triggerName, jobGroup);
}
/**
* 获取任务KEY
* 任务命名规则:TASK_CLASS_NAME + 格式化后的jobId(5位数字,不足补0)
*
* @param jobId 任务ID
* @param jobGroup 任务分组
* @return JobKey 任务键
*/
public static JobKey getJobKey(Integer jobId, String jobGroup) {
// 将任务ID格式化为5位数字,不足前面补0,确保任务名称的唯一性和规范性
String jobKeyId = String.format("%05d", jobId);
String jobName = ScheduleConstant.TASK_CLASS_NAME + jobKeyId;
log.debug("生成任务KEY:任务名称={},任务分组={}", jobName, jobGroup);
return JobKey.jobKey(jobName, jobGroup);
}
/**
* 获取表达式触发器
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @return CronTrigger Cron表达式触发器
* @throws ScheduleException 当获取触发器失败时抛出
*/
public static CronTrigger getCronTrigger(Scheduler scheduler, Integer jobId, String jobGroup) {
try {
TriggerKey triggerKey = getTriggerKey(jobId, jobGroup);
return (CronTrigger) scheduler.getTrigger(triggerKey);
} catch (SchedulerException e) {
log.error("获取定时任务CronTrigger出现异常,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("获取定时任务CronTrigger出现异常");
}
}
/**
* 创建定时任务(基于ScheduleJob对象)
*
* @param scheduler Quartz调度器实例
* @param scheduleJob 定时任务配置对象
* @throws ScheduleException 当创建任务失败时抛出
*/
public static void createScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) {
createScheduleJob(scheduler,
scheduleJob.getId(),
scheduleJob.getJobGroup(),
scheduleJob.getCronExpression(),
scheduleJob.getIsSync(),
scheduleJob);
}
/**
* 创建定时任务(基于参数)
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @param cronExpression Cron表达式,定义任务执行时间规则
* @param isSync 是否同步执行:1-同步 0-异步
* @param param 任务参数,会传递给Job执行时使用
* @throws ScheduleException 当创建任务失败时抛出
*/
public static void createScheduleJob(Scheduler scheduler, Integer jobId, String jobGroup,
String cronExpression, Integer isSync, Object param) {
try {
// 根据同步/异步标识选择对应的Job工厂类
Class<? extends Job> jobClass = isSync.equals(1) ? SyncJobFactory.class : AsyncJobFactory.class;
log.info("创建{}定时任务,任务ID:{},任务分组:{},Cron表达式:{}",
isSync.equals(1) ? "同步" : "异步", jobId, jobGroup, cronExpression);
// 1. 构建JobDetail(任务详情)
JobDetail jobDetail = JobBuilder.newJob(jobClass)
.withIdentity(getJobKey(jobId, jobGroup))
.build();
// 2. 构建CronScheduleBuilder(Cron调度构建器)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
// 3. 构建CronTrigger(Cron触发器)
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(jobId, jobGroup))
.withSchedule(scheduleBuilder)
.build();
// 4. 设置任务触发器信息到参数对象中
String jobTrigger = trigger.getKey().getName();
if (param instanceof ScheduleJob scheduleJob) {
scheduleJob.setJobTrigger(jobTrigger);
}
// 5. 将任务参数放入JobDataMap,供Job执行时获取
jobDetail.getJobDataMap().put(ScheduleConstant.TASK_SCHEDULE_PARAM, param);
// 6. 调度任务
scheduler.scheduleJob(jobDetail, trigger);
log.info("定时任务创建成功,任务ID:{},任务分组:{}", jobId, jobGroup);
} catch (SchedulerException e) {
log.error("创建定时任务失败,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("创建定时任务失败");
}
}
/**
* 立即运行一次任务
* 注意:此方法只触发任务立即执行一次,不影响原有的调度计划
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @throws ScheduleException 当触发任务失败时抛出
*/
public static void runOnce(Scheduler scheduler, Integer jobId, String jobGroup) {
JobKey jobKey = getJobKey(jobId, jobGroup);
try {
log.info("立即执行定时任务,任务ID:{},任务分组:{}", jobId, jobGroup);
scheduler.triggerJob(jobKey);
} catch (SchedulerException e) {
log.error("立即执行定时任务失败,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("立即执行定时任务失败");
}
}
/**
* 暂停定时任务
* 暂停后任务将不再触发执行,但任务配置仍然保留
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @throws ScheduleException 当暂停任务失败时抛出
*/
public static void pauseJob(Scheduler scheduler, Integer jobId, String jobGroup) {
JobKey jobKey = getJobKey(jobId, jobGroup);
try {
log.info("暂停定时任务,任务ID:{},任务分组:{}", jobId, jobGroup);
scheduler.pauseJob(jobKey);
} catch (SchedulerException e) {
log.error("暂停定时任务失败,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("暂停定时任务失败");
}
}
/**
* 恢复定时任务
* 将暂停的任务重新激活,按照原有的调度计划继续执行
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @throws ScheduleException 当恢复任务失败时抛出
*/
public static void resumeJob(Scheduler scheduler, Integer jobId, String jobGroup) {
JobKey jobKey = getJobKey(jobId, jobGroup);
try {
log.info("恢复定时任务,任务ID:{},任务分组:{}", jobId, jobGroup);
scheduler.resumeJob(jobKey);
} catch (SchedulerException e) {
log.error("恢复定时任务失败,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("恢复定时任务失败");
}
}
/**
* 更新定时任务(基于ScheduleJob对象)
* 主要更新Cron表达式,其他配置保持不变
*
* @param scheduler Quartz调度器实例
* @param scheduleJob 定时任务配置对象
* @throws ScheduleException 当更新任务失败时抛出
*/
public static void updateScheduleJob(Scheduler scheduler, ScheduleJob scheduleJob) {
updateScheduleJob(scheduler,
scheduleJob.getId(),
scheduleJob.getJobGroup(),
scheduleJob.getCronExpression(),
scheduleJob.getIsSync(),
scheduleJob);
}
/**
* 更新定时任务(基于参数)
* 主要更新触发器的Cron表达式,解决集群环境中状态同步问题
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @param cronExpression 新的Cron表达式
* @param isSync 是否同步执行(此参数在当前实现中未使用,保留为了接口一致性)
* @param param 任务参数(此参数在当前实现中未使用,保留为了接口一致性)
* @throws ScheduleException 当更新任务失败时抛出
*/
public static void updateScheduleJob(Scheduler scheduler, Integer jobId, String jobGroup,
String cronExpression, Integer isSync, Object param) {
try {
log.info("更新定时任务,任务ID:{},任务分组:{},新的Cron表达式:{}", jobId, jobGroup, cronExpression);
TriggerKey triggerKey = getTriggerKey(jobId, jobGroup);
// 1. 构建新的Cron调度器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
// 2. 获取原有的触发器
CronTrigger oldTrigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 3. 基于原有触发器构建新的触发器(只更新调度表达式)
CronTrigger newTrigger = oldTrigger.getTriggerBuilder()
.withIdentity(triggerKey)
.withSchedule(scheduleBuilder)
.build();
// 4. 检查触发器当前状态
Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);
// 5. 忽略状态为PAUSED的任务,解决集群环境中状态同步问题
// 在集群环境下,如果任务在其他节点被暂停,在当前节点更新时不应该重新激活任务
if (!triggerState.name().equalsIgnoreCase("PAUSED")) {
scheduler.rescheduleJob(triggerKey, newTrigger);
log.info("定时任务更新成功,任务ID:{},任务分组:{}", jobId, jobGroup);
} else {
log.warn("定时任务处于暂停状态,跳过更新操作,任务ID:{},任务分组:{}", jobId, jobGroup);
}
} catch (SchedulerException e) {
log.error("更新定时任务失败,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("更新定时任务失败");
}
}
/**
* 删除定时任务
* 删除后任务将完全移除,包括任务配置和执行历史
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @throws ScheduleException 当删除任务失败时抛出
*/
public static void deleteScheduleJob(Scheduler scheduler, Integer jobId, String jobGroup) {
try {
JobKey jobKey = getJobKey(jobId, jobGroup);
log.info("删除定时任务,任务ID:{},任务分组:{}", jobId, jobGroup);
scheduler.deleteJob(jobKey);
} catch (SchedulerException e) {
log.error("删除定时任务失败,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("删除定时任务失败");
}
}
/**
* 检查定时任务是否存在
*
* @param scheduler Quartz调度器实例
* @param jobId 任务ID
* @param jobGroup 任务分组
* @return boolean true-存在 false-不存在
* @throws ScheduleException 当检查任务存在状态失败时抛出
*/
public static boolean checkExists(Scheduler scheduler, Integer jobId, String jobGroup) {
try {
JobKey jobKey = getJobKey(jobId, jobGroup);
boolean exists = scheduler.checkExists(jobKey);
log.debug("检查定时任务是否存在,任务ID:{},任务分组:{},结果:{}", jobId, jobGroup, exists);
return exists;
} catch (SchedulerException e) {
log.error("检查定时任务是否存在失败,任务ID:{},任务分组:{}", jobId, jobGroup, e);
throw new ScheduleException("检查定时任务是否存在失败");
}
}
}