1 SQL(定时任务表)
创建定时任务表sql:
create table t_job(
job_id varchar(36) primary key COMMENT '定时任务ID',
job_name varchar(200) DEFAULT NULL COMMENT '定时任务名称',
status varchar(1) DEFAULT null comment '有效状态',
enable_flag varchar(1) DEFAULT null comment '可见状态',
cron_expression varchar(200) DEFAULT null comment 'cron表达式',
execute_target varchar(500) DEFAULT null comment '调用目标字符串'
) comment '定时任务表';
添加定时任务数据sql:
insert into t_job(job_id,job_name,status,enable_flag,cron_expression,execute_target) values('6ca3e86712a645aea01ebbebbb2277d5','测试定时任务','1','1','0/30 * * * * ?','testTask.test(\'6ca3e86712a645aea01ebbebbb2277d5\')');
insert into t_job(job_id,job_name,status,enable_flag,cron_expression,execute_target) values('6ca3e86712a645aea01ebbebbb2277d6','测试定时任务2','1','1','0/10 * * * * ?','testTask.test(\'6ca3e86712a645aea01ebbebbb2277d6\')');
2 Maven依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--quartz定时任务-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!--hutool工具包-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.1</version>
</dependency>
3 applicattion.properties
server.port=8081
#数据库连接池设置
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=root
#mybatis的相关配置
mybatis.mapper-locations=classpath:mapper/*.xml
4 实体类(定时任务)
TJob.java:
package com.entity;
import lombok.Data;
@Data
public class TJob {
/**
* 定时任务ID
*/
private String jobId;
/**
* 定时任务名称
*/
private String jobName;
/**
* 有效状态
*/
private String status;
/**
* 可见状态
*/
private String enableFlag;
/**
* cron表达式
*/
private String cronExpression;
/**
* 调用目标字符串
*/
private String executeTarget;
}
5 Mapper
TJobMapper.java:
package com.mapper;
import com.entity.TJob;
import java.util.List;
public interface TJobMapper {
/**
* 获取所有定时任务信息
* @return
*/
List<TJob> getAllJobList();
}
TJobMapper.xml:
<?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.mapper.TJobMapper">
<select id="getAllJobList" resultType="com.entity.TJob">
select job_id jobId,job_name jobName,status,enable_flag enableFlag,cron_expression cronExpression
,execute_target executeTarget
from t_job
</select>
</mapper>
6 Service
TJobService.java:
package com.service;
public interface TJobService {
}
TJobServiceImpl.java:
package com.service.impl;
import cn.hutool.core.util.StrUtil;
import com.entity.TJob;
import com.mapper.TJobMapper;
import com.quartz.QuartJob;
import com.service.TJobService;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class TJobServiceImpl implements TJobService {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Autowired
private TJobMapper jobMapper;
/**
* 初始化定时任务
*/
@PostConstruct
public void init() {
//获取调度器
Scheduler scheduler = schedulerFactoryBean.getScheduler();
//获取所有定时任务
List<TJob> jobList = jobMapper.getAllJobList();
//定时任务不存在
if (jobList == null || jobList.size() <= 0) {
return;
}
//获取有效的定时任务
jobList = jobList.stream().filter(x -> StrUtil.equals(x.getStatus(), "1")).collect(Collectors.toList());
//没有需要创建的定时任务
if (jobList == null || jobList.size() <= 0) {
return;
}
try {
//清空调动任务
scheduler.clear();
for (TJob job : jobList) {
createJob(job,scheduler);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建定时任务
*
* @param job 定时任务
* @param scheduler 调度器
*/
public void createJob(TJob job, Scheduler scheduler) throws Exception {
if (job == null) {
return;
}
//触发器主键
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobId(), null);
// 表达式调度构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
//定时任务主键
JobKey jobKey = JobKey.jobKey(job.getJobId(), null);
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(QuartJob.class).withIdentity(jobKey).build();
//触发器
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(cronScheduleBuilder).build();
// 放入参数,运行时的方法可以获取
jobDetail.getJobDataMap().put("job", job);
// 判断定时任务存在
if (scheduler.checkExists(jobKey)) {
// 定时任务已存在则重新设置触发器
scheduler.rescheduleJob(triggerKey, cronTrigger);
} else {
// 定时任务不存在则创建定时任务
scheduler.scheduleJob(jobDetail, cronTrigger);
}
}
}
7 Job(定时任务)实现类
QuartJob.java:
package com.quartz;
import cn.hutool.core.date.DateUtil;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
public class QuartJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
try {
before(context);
doExecute(context);
after(context, null);
} catch (Exception e) {
System.out.println("定时任务执行失败:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
after(context, e);
}
}
/**
* 执行前
*
* @param context 工作执行上下文对象
*/
protected void before(JobExecutionContext context) {
System.out.println("------------");
System.out.println("开始执行定时任务:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
}
/**
* 执行后
*
* @param context 工作执行上下文对象
*/
protected void after(JobExecutionContext context, Exception e) {
System.out.println("定时任务执行结束:" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
}
/**
* 执行方法
*
* @param context 工作执行上下文对象
* @throws Exception 执行过程中的异常
*/
protected void doExecute(JobExecutionContext context) throws Exception {
//获取JobDetail中关联的数据
TJob job = (TJob) context.getJobDetail().getJobDataMap().get("job");
System.out.println("定时任务正在执行中");
System.out.println("当前时间 :" + DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss") + "\n任务名(" + job.getJobName()+")");
}
}
8 InvokeUtil(任务执行工具类)
InvokeUtil.java:
package com.util;
import cn.hutool.core.util.StrUtil;
import com.entity.TJob;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
public class InvokeUtil {
/**
* 执行方法
*
* @param job 系统任务
*/
public static void invokeMethod(TJob job) throws Exception {
String executeTarget = job.getExecuteTarget();
if (StrUtil.isBlank(executeTarget)) {
return;
}
String beanName = executeTarget.substring(0, executeTarget.indexOf("."));
if (StrUtil.isBlank(beanName)) {
return;
}
String methodName = executeTarget.substring(executeTarget.indexOf(".") + 1, executeTarget.indexOf("("));
if (StrUtil.isBlank(methodName)) {
return;
}
List<Object[]> methodParams = getMethodParams(executeTarget);
//创建调用目标实例
Object bean = null;
if (beanName.indexOf(".") < 0) {
//bean名为自定义的实例名
bean = SpringUtil.getBean(beanName);
} else {
//bean名带包名路径
bean = Class.forName(beanName).newInstance();
}
if (methodParams != null && 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);
}
}
/**
* 获取参数类型
*
* @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;
}
/**
* 获取method方法参数相关列表
*
* @param invokeTarget 目标字符串
* @return method方法相关参数列表
*/
public static List<Object[]> getMethodParams(String invokeTarget) {
String methodStr = invokeTarget.substring(invokeTarget.indexOf("(") + 1, invokeTarget.indexOf(")"));
if (StrUtil.isBlank(methodStr)) {
return null;
}
String[] methodParams = methodStr.split(",");
List<Object[]> classs = new LinkedList<>();
for (int i = 0; i < methodParams.length; i++) {
String str = StrUtil.isBlank(methodParams[i]) ? "" : methodParams[i].trim();
;
// String字符串类型,包含'
if (str.contains("'")) {
classs.add(new Object[]{str.replace("'", ""), String.class});
}
// boolean布尔类型,等于true或者false
else if (StrUtil.equals(str.toLowerCase(), "true") || StrUtil.equals(str.toLowerCase(), "false")) {
classs.add(new Object[]{Boolean.valueOf(str), Boolean.class});
}
// long长整形,包含L
else if (str.toUpperCase().contains("L")) {
classs.add(new Object[]{Long.valueOf(str.toUpperCase().replace("L", "")), Long.class});
}
// double浮点类型,包含D
else if (str.toUpperCase().contains("D")) {
classs.add(new Object[]{Double.valueOf(str.toUpperCase().replace("D", "")), Double.class});
}
// 其他类型归类为整形
else {
classs.add(new Object[]{Integer.valueOf(str), Integer.class});
}
}
return classs;
}
}
9 SpringUtil(Spring工具类)
SpringUtil.java:
package com.util;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.stereotype.Component;
@Component
public class SpringUtil implements BeanFactoryPostProcessor {
/**
* Spring应用上下文环境
*/
private static ConfigurableListableBeanFactory beanFactory;
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
SpringUtil.beanFactory=configurableListableBeanFactory;
}
/**
* 获取对象
*
* @param name
* @return Object 一个以所给名字注册的bean的实例
* @throws org.springframework.beans.BeansException
*
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) throws BeansException
{
return (T) beanFactory.getBean(name);
}
}
10 Task(定时任务调用方法)
TestTask.java:
package com.task;
import org.springframework.stereotype.Component;
@Component("testTask")
public class TestTask {
/**
* 定时任务调用方法
*
* @param jobId 定时任务ID
*/
public void test(String jobId) {
System.out.println("当前执行的定时任务ID:" + jobId);
}
}
11 Application(启动类)
QuartzApplication.java:
package com;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@MapperScan("com.mapper")
@SpringBootApplication
public class QuartzApplication {
public static void main(String[] args) {
SpringApplication.run(QuartzApplication.class, args);
}
}