动态定时任务【闹钟】

SpringBoot 实现动态往数据库中添加时间点,使程序在规定的时间点执行任务

1.依赖引入 配置文件
 		<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
2.表以及设计

动态定时任务【闹钟】_第1张图片

3.代码实现
3.1 任务添加线程池里面去跑
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;
    }

}
3.2 查询数据库,找到数据,添加定时任务
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>
4. 结果

动态定时任务【闹钟】_第2张图片

动态定时任务【闹钟】_第3张图片

你可能感兴趣的:(java,mybatis,spring,boot)