<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>1.3.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>5.1.47version>
dependency>
server:
port: 9094
spring:
datasource:
url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root123
driver-class-name: com.mysql.jdbc.Driver
mybatis:
mapper-locations: classpath:com/example/**/mapper/*.xml
type-aliases-package: com.example.demo.dto
package com.example.demo.config;
import org.springframework.scheduling.SchedulingException;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.stereotype.Component;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
/**
* @author 胡萝卜
*/
@Component
public class MyScheduling implements SchedulingConfigurer {
/** 定时任务注册器 */
private ScheduledTaskRegistrar taskRegistrar;
private Set<ScheduledFuture<?>> scheduledFutures = null;
/** 存放所有定时任务 */
private Map<String, ScheduledFuture<?>> taskMap = new ConcurrentHashMap<>();
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
this.taskRegistrar = taskRegistrar;
}
@SuppressWarnings("unchecked")
private Set<ScheduledFuture<?>> getScheduledFutures() {
if (scheduledFutures == null) {
try {
scheduledFutures = (Set<ScheduledFuture<?>>) getProperty(taskRegistrar, "scheduledTasks");
}
catch (NoSuchFieldException e) {
throw new SchedulingException("not found scheduledFutures field.");
}
}
return scheduledFutures;
}
/**
* 添加定时任务
* @param taskId 定时任务唯一标识
* @param runnable 定时任务执行的具体逻辑
* @param trigger 下一个定时任务执行时机的触发器
*/
public void addTriggerTask(String taskId, Runnable runnable, Trigger trigger) {
// 若定时任务已经存在,则进行覆盖操作(即先移除)
if (taskMap.containsKey(taskId)) {
removeTriggerTask(taskId);
}
// 添加定时任务
ScheduledFuture<?> schedule = Objects.requireNonNull(taskRegistrar.getScheduler()).schedule(runnable, trigger);
getScheduledFutures().add(schedule);
taskMap.put(taskId, schedule);
}
/**
* 移除定时任务
* @param taskId 定时任务 id
*/
public void removeTriggerTask(String taskId) {
ScheduledFuture<?> future = taskMap.get(taskId);
if (future != null) {
future.cancel(true);
}
taskMap.remove(taskId);
getScheduledFutures().remove(future);
}
public static Field findField(Class<?> clazz, String name) {
try {
return clazz.getField(name);
} catch (NoSuchFieldException ex) {
return findDeclaredField(clazz, name);
}
}
public static Field findDeclaredField(Class<?> clazz, String name) {
try {
return clazz.getDeclaredField(name);
} catch (NoSuchFieldException ex) {
if (clazz.getSuperclass() != null) {
return findDeclaredField(clazz.getSuperclass(), name);
}
return null;
}
}
public static Object getProperty(Object obj, String name) throws NoSuchFieldException {
Object value = null;
Field field = findField(obj.getClass(), name);
if (field == null) {
throw new NoSuchFieldException("no such field [" + name + "]");
}
boolean accessible = field.isAccessible();
field.setAccessible(true);
try {
value = field.get(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
field.setAccessible(accessible);
return value;
}
}
package com.example.demo.service;
import com.example.demo.config.MyScheduling;
import com.example.demo.dto.TaskCron;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author 胡萝卜
*/
@Component
@Slf4j
public class TaskScheduling implements ApplicationRunner {
private Logger log= LoggerFactory.getLogger(TaskScheduling.class);
@Autowired
MyScheduling myScheduling;
@Autowired
TaskCronService taskCronService;
@Override
public void run(ApplicationArguments args) throws Exception {
// 在项目启动后,初始化任务调度器,如果是一个页面去添加时间,就是再添加成功或者修改成功,进行初始化一次
initTaskScheduling();
}
public void initTaskScheduling() {
//查询数据库里面的所以任务
List<TaskCron> taskCrons = taskCronService.selectTaskCron();
for(TaskCron taskCron:taskCrons){
log.info("装载定时任务ID:" + taskCron.getId());
myScheduling.addTriggerTask(String.valueOf(taskCron.getId()), getTaskRunnable(taskCron), getTaskTrigger(taskCron));
}
}
/** 获取指定的任务执行逻辑 */
public Runnable getTaskRunnable(TaskCron taskCron) {
return () -> {
//要操作那些业务逻辑
if (taskCron != null){
//执行业务
taskCronService.updateTaskCron(taskCron.getId());
}
};
}
/** 获取指定任务所属的触发器 */
public Trigger getTaskTrigger(TaskCron taskCron) {
return triggerContext -> {
// 通过获取该用户最近的未完成的日程,解析出下一个通知的发送时间
String cron;
//时间todo
cron=taskCron.getCronTime();
//Task nearestTask = taskService.getNearestTask(groupId);
if (taskCron != null) {
// 任务存在的话,将执行时间解析为 cron 表达式
// 如果时间已经超过了,则立即执行,否则常规解析
log.info("解析出的 cron:" + cron);
}
// 返回执行周期
return new CronTrigger(cron).nextExecutionTime(triggerContext);
};
}
}
mapper.xml
package com.example.demo.service;
import com.example.demo.dto.TaskCron;
import com.example.demo.repository.dao.TaskCronMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @author 胡萝卜
*/
@Service
public class TaskCronService {
@Autowired
private TaskCronMapper taskCronMapper;
public void updateTaskCron(Integer id){
taskCronMapper.update(id);
}
public List<TaskCron> selectTaskCron(){
return taskCronMapper.selectTaskCron();
}
}
<update id="update">
update taskCron
set status=1,frequency=frequency+1,updateTime=NOW()
where id=#{id};
update>
<select id="selectTaskCron" resultMap="BaseResultMap">
select * from taskCron order by id
select>