first commit

This commit is contained in:
zhengchengqiang
2024-11-11 09:53:47 +08:00
commit 3c26b78bbe
1593 changed files with 73406 additions and 0 deletions
@@ -0,0 +1,59 @@
package com.alonginfo.quartz.config;
import org.quartz.Scheduler;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import java.io.IOException;
import java.util.Properties;
/**
* @Description Qartz配置, 搭配quartz.properties文件自定义配置, 该处目的使定时任务持久化
* @Author Haoxs
* @Date 2021-04-29 11:11
*/
@Configuration
public class SchedulerConfig {
@Autowired
private JobFactory jobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
try {
schedulerFactoryBean.setOverwriteExistingJobs(true);
schedulerFactoryBean.setQuartzProperties(quartzProperties());
schedulerFactoryBean.setOverwriteExistingJobs(true);
schedulerFactoryBean.setJobFactory(jobFactory);
} catch (IOException e) {
e.printStackTrace();
}
return schedulerFactoryBean;
}
/**
* 读取quartz.properties文件
* 将值初始化
*
* @return
* @throws IOException
*/
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
@Bean(name = "scheduler")
public Scheduler scheduler() {
return schedulerFactoryBean().getScheduler();
}
}
@@ -0,0 +1,191 @@
package com.alonginfo.quartz.domain;
import com.alonginfo.common.enums.ScheduleConstants;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
/**
* @Description
* @Author Haoxs
* @Date 2021-05-07 10:43
*/
public class SysJob implements Serializable {
/**
* 任务Id
*/
private Long jobId;
/**
* 任务名称
*/
private String jobName;
/**
* 任务组名
*/
private String jobGroup;
/**
* 调用目标字符串
*/
private String invokeTarget;
/**
* cron表达式
*/
private String cronExpression;
/**
* cron计划策略 0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行
*/
private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
/**
* 是否并发执行 0-允许 1-禁止
*/
private String concurrent;
/**
* 任务状态 0-正常 1-暂停
*/
private String status;
private String createBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
private String updateBy;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
private String remark;
public Long getJobId() {
return jobId;
}
public void setJobId(Long jobId) {
this.jobId = jobId;
}
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getJobGroup() {
return jobGroup;
}
public void setJobGroup(String jobGroup) {
this.jobGroup = jobGroup;
}
public String getInvokeTarget() {
return invokeTarget;
}
public void setInvokeTarget(String invokeTarget) {
this.invokeTarget = invokeTarget;
}
public String getCronExpression() {
return cronExpression;
}
public void setCronExpression(String cronExpression) {
this.cronExpression = cronExpression;
}
public String getMisfirePolicy() {
return misfirePolicy;
}
public void setMisfirePolicy(String misfirePolicy) {
this.misfirePolicy = misfirePolicy;
}
public String getConcurrent() {
return concurrent;
}
public void setConcurrent(String concurrent) {
this.concurrent = concurrent;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getCreateBy() {
return createBy;
}
public void setCreateBy(String createBy) {
this.createBy = createBy;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String getUpdateBy() {
return updateBy;
}
public void setUpdateBy(String updateBy) {
this.updateBy = updateBy;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
@Override
public String toString() {
return "SysJob{" +
"jobId=" + jobId +
", jobName='" + jobName + '\'' +
", jobGroup='" + jobGroup + '\'' +
", invokeTarget='" + invokeTarget + '\'' +
", cronExpression='" + cronExpression + '\'' +
", misfirePolicy='" + misfirePolicy + '\'' +
", concurrent='" + concurrent + '\'' +
", status='" + status + '\'' +
", createBy='" + createBy + '\'' +
", createTime=" + createTime +
", updateBy='" + updateBy + '\'' +
", updateTime=" + updateTime +
", remark='" + remark + '\'' +
'}';
}
}
@@ -0,0 +1,28 @@
package com.alonginfo.quartz.factory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author Haoxs
* @Date 2021-05-06 18:57
*/
@Component
public class JobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
@@ -0,0 +1,28 @@
package com.alonginfo.quartz.job;
import com.alonginfo.common.utils.StringUtils;
import org.springframework.stereotype.Component;
/**
* @Description 定时任务调度测试
* @Author Haoxs
* @Date 2021-05-06 19:05
*/
@Component("ryTask")
public class RyTask
{
public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
{
System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
}
public void ryParams(String params)
{
System.out.println("执行有参方法:" + params);
}
public void ryNoParams()
{
System.out.println("执行无参方法");
}
}
@@ -0,0 +1,25 @@
package com.alonginfo.quartz.listener;
import com.alonginfo.quartz.service.InitService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* @Description 监听器
* @Author Haoxs
* @Date 2021-05-06 17:37
*/
@Component
@Order(value = 1)
public class SchedulerJobInitListener implements CommandLineRunner {
@Autowired
private InitService initService;
@Override
public void run(String... args) throws Exception {
initService.initSchedule();
}
}
@@ -0,0 +1,20 @@
package com.alonginfo.quartz.mapper;
import com.alonginfo.quartz.domain.SysJob;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @Description 定时任务mapper
* @Author Haoxs
* @Date 2021-05-06 18:31
*/
@Repository
@Mapper
public interface InitMapper {
List<SysJob> getList();
}
@@ -0,0 +1,18 @@
package com.alonginfo.quartz.service;
import com.alonginfo.common.exception.job.TaskException;
import org.quartz.SchedulerException;
/**
* @Description
* @Author Haoxs
* @Date 2021-05-06 18:10
*/
public interface InitService {
/**
* 初始化定时任务
*/
void initSchedule() throws SchedulerException, TaskException;
}
@@ -0,0 +1,40 @@
package com.alonginfo.quartz.service.impl;
import com.alonginfo.common.exception.job.TaskException;
import com.alonginfo.quartz.domain.SysJob;
import com.alonginfo.quartz.mapper.InitMapper;
import com.alonginfo.quartz.service.InitService;
import com.alonginfo.quartz.utils.ScheduleUtils;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @Description
* @Author Haoxs
* @Date 2021-05-06 18:12
*/
@Service
public class InitServiceImpl implements InitService {
@Autowired
private Scheduler scheduler;
@Autowired
private InitMapper initMapper;
/**
* 初始化定时任务
*/
@Override
public void initSchedule() throws SchedulerException, TaskException {
scheduler.clear();
List<SysJob> jobList = initMapper.getList();
for (SysJob job : jobList) {
ScheduleUtils.createScheduleJob(scheduler, job);
}
}
}
@@ -0,0 +1,102 @@
package com.alonginfo.quartz.utils;
import com.alonginfo.common.enums.ScheduleConstants;
import com.alonginfo.common.utils.bean.BeanUtils;
import com.alonginfo.quartz.domain.SysJob;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
/**
* 抽象quartz调用
*
* @author lcdop
*/
public abstract class AbstractQuartzJob implements Job
{
private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
/**
* 线程本地变量
*/
private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
@Override
public void execute(JobExecutionContext context) throws JobExecutionException
{
SysJob sysJob = new SysJob();
BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
try
{
before(context, sysJob);
if (sysJob != null)
{
doExecute(context, sysJob);
}
after(context, sysJob, null);
}
catch (Exception e)
{
log.error("任务执行异常 - :", e);
after(context, sysJob, e);
}
}
/**
* 执行前
*
* @param context 工作执行上下文对象
* @param sysJob 系统计划任务
*/
protected void before(JobExecutionContext context, SysJob sysJob)
{
threadLocal.set(new Date());
}
/**
* 执行后
*
* @param context 工作执行上下文对象
* @param sysJob 系统计划任务
*/
protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
{
Date startTime = threadLocal.get();
threadLocal.remove();
//
// final SysJobLog sysJobLog = new SysJobLog();
// sysJobLog.setJobName(sysJob.getJobName());
// sysJobLog.setJobGroup(sysJob.getJobGroup());
// sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
// sysJobLog.setStartTime(startTime);
// sysJobLog.setStopTime(new Date());
// long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
// sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
// if (e != null)
// {
// sysJobLog.setStatus(Constants.FAIL);
// String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
// sysJobLog.setExceptionInfo(errorMsg);
// }
// else
// {
// sysJobLog.setStatus(Constants.SUCCESS);
// }
//
// // 写入数据库当中
// SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
}
/**
* 执行方法,由子类重载
*
* @param context 工作执行上下文对象
* @param sysJob 系统计划任务
* @throws Exception 执行过程中的异常
*/
protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
}
@@ -0,0 +1,64 @@
package com.alonginfo.quartz.utils;
import org.quartz.CronExpression;
import java.text.ParseException;
import java.util.Date;
/**
* cron表达式工具类
*
* @author lcdop
*
*/
public class CronUtils
{
/**
* 返回一个布尔值代表一个给定的Cron表达式的有效性
*
* @param cronExpression Cron表达式
* @return boolean 表达式是否有效
*/
public static boolean isValid(String cronExpression)
{
return CronExpression.isValidExpression(cronExpression);
}
/**
* 返回一个字符串值,表示该消息无效Cron表达式给出有效性
*
* @param cronExpression Cron表达式
* @return String 无效时返回表达式错误描述,如果有效返回null
*/
public static String getInvalidMessage(String cronExpression)
{
try
{
new CronExpression(cronExpression);
return null;
}
catch (ParseException pe)
{
return pe.getMessage();
}
}
/**
* 返回下一个执行时间根据给定的Cron表达式
*
* @param cronExpression Cron表达式
* @return Date 下次Cron表达式执行时间
*/
public static Date getNextExecution(String cronExpression)
{
try
{
CronExpression cron = new CronExpression(cronExpression);
return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
}
catch (ParseException e)
{
throw new IllegalArgumentException(e.getMessage());
}
}
}
@@ -0,0 +1,184 @@
package com.alonginfo.quartz.utils;
import com.alonginfo.common.utils.StringUtils;
import com.alonginfo.common.utils.spring.SpringUtils;
import com.alonginfo.quartz.domain.SysJob;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
/**
* 任务执行工具
*
* @author lcdop
*/
public class JobInvokeUtil
{
/**
* 执行方法
*
* @param sysJob 系统任务
*/
public static void invokeMethod(SysJob sysJob) throws Exception
{
String invokeTarget = sysJob.getInvokeTarget();
String beanName = getBeanName(invokeTarget);
String methodName = getMethodName(invokeTarget);
List<Object[]> methodParams = getMethodParams(invokeTarget);
if (!isValidClassName(beanName))
{
Object bean = SpringUtils.getBean(beanName);
invokeMethod(bean, methodName, methodParams);
}
else
{
Object bean = Class.forName(beanName).newInstance();
invokeMethod(bean, methodName, methodParams);
}
}
/**
* 调用任务方法
*
* @param bean 目标对象
* @param methodName 方法名称
* @param methodParams 方法参数
*/
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().getDeclaredMethod(methodName, getMethodParamsType(methodParams));
method.invoke(bean, getMethodParamsValue(methodParams));
}
else
{
Method method = bean.getClass().getDeclaredMethod(methodName);
method.invoke(bean);
}
}
/**
* 校验是否为为class包名
*
* @param invokeTarget 名称
* @return true是 false否
*/
public static boolean isValidClassName(String invokeTarget)
{
return StringUtils.countMatches(invokeTarget, ".") > 1;
}
/**
* 获取bean名称
*
* @param invokeTarget 目标字符串
* @return bean名称
*/
public static String getBeanName(String invokeTarget)
{
String beanName = StringUtils.substringBefore(invokeTarget, "(");
return StringUtils.substringBeforeLast(beanName, ".");
}
/**
* 获取bean方法
*
* @param invokeTarget 目标字符串
* @return method方法
*/
public static String getMethodName(String invokeTarget)
{
String methodName = StringUtils.substringBefore(invokeTarget, "(");
return StringUtils.substringAfterLast(methodName, ".");
}
/**
* 获取method方法参数相关列表
*
* @param invokeTarget 目标字符串
* @return method方法相关参数列表
*/
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]);
// String字符串类型,包含'
if (StringUtils.contains(str, "'"))
{
classs.add(new Object[] { StringUtils.replace(str, "'", ""), String.class });
}
// boolean布尔类型,等于true或者false
else if (StringUtils.equals(str, "true") || StringUtils.equalsIgnoreCase(str, "false"))
{
classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
}
// long长整形,包含L
else if (StringUtils.containsIgnoreCase(str, "L"))
{
classs.add(new Object[] { Long.valueOf(StringUtils.replaceIgnoreCase(str, "L", "")), Long.class });
}
// double浮点类型,包含D
else if (StringUtils.containsIgnoreCase(str, "D"))
{
classs.add(new Object[] { Double.valueOf(StringUtils.replaceIgnoreCase(str, "D", "")), Double.class });
}
// 其他类型归类为整形
else
{
classs.add(new Object[] { Integer.valueOf(str), Integer.class });
}
}
return classs;
}
/**
* 获取参数类型
*
* @param methodParams 参数相关列表
* @return 参数类型列表
*/
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 参数相关列表
* @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,21 @@
package com.alonginfo.quartz.utils;
import com.alonginfo.quartz.domain.SysJob;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
/**
* 定时任务处理(禁止并发执行)
*
* @author lcdop
*
*/
@DisallowConcurrentExecution
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
{
@Override
protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
{
JobInvokeUtil.invokeMethod(sysJob);
}
}
@@ -0,0 +1,19 @@
package com.alonginfo.quartz.utils;
import com.alonginfo.quartz.domain.SysJob;
import org.quartz.JobExecutionContext;
/**
* 定时任务处理(允许并发执行)
*
* @author lcdop
*
*/
public class QuartzJobExecution extends AbstractQuartzJob
{
@Override
protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
{
JobInvokeUtil.invokeMethod(sysJob);
}
}
@@ -0,0 +1,104 @@
package com.alonginfo.quartz.utils;
import com.alonginfo.common.enums.ScheduleConstants;
import com.alonginfo.common.exception.job.TaskException;
import com.alonginfo.common.exception.job.TaskException.Code;
import com.alonginfo.quartz.domain.SysJob;
import org.quartz.*;
/**
* 定时任务工具类
*
* @author lcdop
*
*/
public class ScheduleUtils
{
/**
* 得到quartz任务类
*
* @param sysJob 执行计划
* @return 具体执行任务类
*/
private static Class<? extends Job> getQuartzJobClass(SysJob sysJob)
{
boolean isConcurrent = "0".equals(sysJob.getConcurrent());
return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
}
/**
* 构建任务触发对象
*/
public static TriggerKey getTriggerKey(Long jobId, String jobGroup)
{
return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
}
/**
* 构建任务键对象
*/
public static JobKey getJobKey(Long jobId, String jobGroup)
{
return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
}
/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException
{
Class<? extends Job> jobClass = getQuartzJobClass(job);
// 构建job信息
Long jobId = job.getJobId();
String jobGroup = job.getJobGroup();
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
// 表达式调度构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
.withSchedule(cronScheduleBuilder).build();
// 放入参数,运行时的方法可以获取
jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
// 判断是否存在
if (scheduler.checkExists(getJobKey(jobId, jobGroup)))
{
// 防止创建时存在数据问题 先移除,然后在执行创建操作
scheduler.deleteJob(getJobKey(jobId, jobGroup));
}
scheduler.scheduleJob(jobDetail, trigger);
// 暂停任务
if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))
{
scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
}
}
/**
* 设置定时任务策略
*/
public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
throws TaskException
{
switch (job.getMisfirePolicy())
{
case ScheduleConstants.MISFIRE_DEFAULT:
return cb;
case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
return cb.withMisfireHandlingInstructionIgnoreMisfires();
case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
return cb.withMisfireHandlingInstructionFireAndProceed();
case ScheduleConstants.MISFIRE_DO_NOTHING:
return cb.withMisfireHandlingInstructionDoNothing();
default:
throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
+ "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
}
}
}
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.alonginfo.quartz.mapper.InitMapper">
<select id="getList" resultType="com.alonginfo.quartz.domain.SysJob">
SELECT job_id jobId, job_name jobName, job_group jobGroup, invoke_target invokeTarget,
cron_expression cronExpression, misfire_policy misfirePolicy, concurrent, status, create_by createBy,
create_time createTime, update_by updateBy, update_time updateTime, remark
FROM
sys_job
</select>
</mapper>