最近有幸要开发个动态定时任务,这里简单再梳理一下。

Demo的整体结构如下:

pom.xml文件只需要导入一下依赖即可

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.6.0</version>
        </dependency>

 

该动态定时任务主配置类是 ScheduledConfig,代码如下;

/**
 * 定时任务主入口
 */
@Configuration
@EnableScheduling
public class ScheduledConfig implements SchedulingConfigurer {
    @Autowired
    private ApplicationContext context;
    @Autowired
    private DataService dataService;

    private Logger logger = LoggerFactory.getLogger(ScheduledConfig.class);
    //重点方法
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        for (DataCron dataCron : dataService.getAllData()) {
            Class<?> clazz;
            Object task = null;
            try {
                clazz = Class.forName(dataCron.getCronKey());
                task = context.getBean(clazz);
            }  catch (Exception e) {
                logger.error(e.getMessage());
            }
            if(task!=null){
                //根据给定的Trigger添加要触发的 Runnable 任务。
                taskRegistrar.addTriggerTask((Runnable) task, new Trigger() {
                    @Override
                    public Date nextExecutionTime(TriggerContext triggerContext) {
                        String cronExpression = dataService.findByCronKey(dataCron.getCronKey()).getCronExpression();
                        return new CronTrigger(cronExpression).nextExecutionTime(triggerContext);
                    }
                });
            }

        }
    }
    @Bean
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(5);
    }
}

 紧接着是这个类,用于控制任务的执行与否;

public interface ScheduledRunnable extends Runnable {
    /**
     * 实际要处理的任务
     */
    void execute();
    /**
     * 控制定时任务启用或禁用的功能
     */
    @Override
    default void run() {
        DataService dataService = SpringUtils.getBean(DataService.class);
        DataCron scheduledCron = dataService.findByCronKey(this.getClass().getName());
        if (!"1".equals(scheduledCron.getStatus())) {
            // 任务是禁用状态
            return;
        }
        execute();
    }
}

 上面代码使用到的SpringUtils工具类的代码如下:

@Component
public class SpringUtils implements ApplicationContextAware {

    private static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringUtils.context = applicationContext;
    }

    public static <T> T getBean(Class<T> clz) {
        return context.getBean(clz);
    }

    public static Object getBean(String name) {
        return context.getBean(name);
    }

    public ApplicationContext getApplicationContext() {
        return context;
    }

}

真正实现任务调用的类是DynamicProcessTask,具体代码如下:

@Component
public class DynamicProcessTask implements ScheduledRunnable {

    private Logger logger = LoggerFactory.getLogger(DynamicProcessTask.class);

    @Autowired
    private RestTemplate restTemplate;

    private int i;

    @Override
    public void execute() {

        logger.info("Thread Id:{} ---->>> execute times:{}", Thread.currentThread().getId(), ++i);
        // 这里也可以继续抽取
        restTemplate.postForEntity("http://localhost:8080/testCron",null, null);

    }

}

到这里核心类已经走完,剩下的就是获取数据相关类

public interface DataService {
    public List<DataCron> getAllData();

    public DataCron findByCronKey(String str);
}
//DataService实现类
@Service
public class DataServiceImpl implements DataService {

    //模拟数据 真实场景换成数据库数据
    private static List<DataCron> list;

    public DataServiceImpl(){
        list = new ArrayList<>();
        list.add(new DataCron("1","com.demo.task.DynamicProcessTask","0/5 * * * * ?","","1"));
        list.add(new DataCron("2","com.demo.task.DynamicProcessTask2","0 0/2 * * * ?","","1"));
        list.add(new DataCron("3","com.demo.task.DynamicProcessTask3","0 0/1 * * * ?","","1"));
    }
    @Override
    public List<DataCron> getAllData() {
        return list;
    }

    @Override
    public DataCron findByCronKey(String str) {
        for (int i = 0; i < list.size(); i++) {
            DataCron dataCron = list.get(i);
            if(dataCron.getCronKey().equals(str)){
                return dataCron;
            }
        }
        return null;
    }
}

//实体类

public class DataCron {
    private String cronId;
    private String cronKey;
    private String cronExpression;
    private String taskExplain;
    private String status;
//剩下方法自行补全
}

@Configuration
public class RestTemplateConfig {

    private RestTemplate restTemplate;

    @Bean
    public RestTemplate getRestTemplate(RestTemplateBuilder restTemplateBuilder) {
        this.restTemplate = new RestTemplate();
        return restTemplate;
    }
}

最后就是要测试的接口

@RestController
public class TestController {

    private Logger logger = LoggerFactory.getLogger(TestController.class);

    @PostMapping("/testCron")
    public void testCron(){
        logger.info("Thread id : {}  ->>>>>>>>>>>>>>>> testCron",Thread.currentThread().getId());
    }

}

测试效果如下:

参考资料:在Spring Boot中动态实现定时任务配置 - 走看看 (zoukankan.com)

SPRING BOOT 动态定时任务_@航空母舰的博客-CSDN博客_springboot动态定时任务

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐