签入版本
This commit is contained in:
+272
@@ -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;
|
||||
}
|
||||
}
|
||||
+376
@@ -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("检查定时任务是否存在失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user