springboot基于spring task实现动态定时任务(@Scheduled)

前言

平时我们使用@Scheduled注解,每次都需要去修改代码。

现在有需求,需要通过在数据库配置cron表达式,以及控制是否开启关闭、

gitee地址:https://gitee.com/nothix/springboot-dynamic-task.git

github地址: https://github.com/shan165310175/springboot-dynamic-task

数据库表 

create table dynamic_task_config
(
    id          int auto_increment
        primary key,
    name        varchar(255)  null comment '名称',
    remark      varchar(255)  null comment '描述',
    bean_name   varchar(255)  not null comment 'bean名称',
    cron        varchar(56)   not null,
    status      int default 0 null comment '0 ok 1 禁用',
    create_time datetime      null,
    update_time datetime      null,
    constraint dynamic_task_config_beanName_uindex
        unique (bean_name)
);

pom.xml文件



	
		org.springframework.boot
		spring-boot-starter-web
	

	
		org.springframework.boot
		spring-boot-starter-test
		test
	

	
		org.springframework.boot
		spring-boot-starter-actuator
	

	
		org.springframework.boot
		spring-boot-starter-cache
	

	
		org.springframework.boot
		spring-boot-starter-data-redis
	

	
		org.springframework.boot
		spring-boot-configuration-processor
	

	
		org.apache.commons
		commons-pool2
	

	
		commons-io
		commons-io
		2.6
	

	
		mysql
		mysql-connector-java
	

	
		org.apache.httpcomponents
		httpclient
	

	
		io.springfox
		springfox-swagger2
		2.9.2
	

	
		io.springfox
		springfox-swagger-ui
		2.9.2
	

	
		com.thetransactioncompany
		cors-filter
		1.3.2
	

	
		com.alibaba
		druid-spring-boot-starter
		1.1.18
	

	
		com.baomidou
		mybatis-plus-boot-starter
		3.0.7.1
	

	
		org.projectlombok
		lombok
	

	
		commons-lang
		commons-lang
		2.6
	





	
		
			org.springframework.boot
			spring-boot-dependencies
			2.0.4.RELEASE
			pom
			import
		
	



	service-task
	
		
			org.apache.maven.plugins
			maven-compiler-plugin
			
				1.8
				1.8
			
		
		
			org.springframework.boot
			spring-boot-maven-plugin
			
				
					
						repackage
					
				
			
		
	

动态定时任务接口

DyTask接口,所有定时任务类,实现该接口

/**
 * 动态任务
 */
public interface DyTask {
    void run();
}

测试定时任务类

@RegisterTask是自定义类,通过该注解,启动时候可以自动把配置信息存入数据库。

@Component
@Slf4j
public class TestDyTask implements DyTask {

    /**
     * 启动后自动将信息注入到数据库
     */
    @RegisterTask(enable = true, override = false, name = "动态任务1 - 测试", remark = "这是备注", cron = "0 */5 * * * ?", status = 0)
    @Override
    public void run() {
        log.info("TestDyTask 测试任务。。。" + LocalDateTime.now());
    }
}

定时任务操作接口

public interface DyTaskManager {

    /**
     * 直接执行定时任务
     */
    boolean runTask(String beanName);

    /**
     * 开始定时任务
     *
     * @param beanName
     * @param cron
     *
     * @return
     */
    boolean scheduleTask(String beanName, String cron);

    /**
     * 取消定时任务
     *
     * @param beanName
     *
     * @return
     */
    boolean cancelTask(String beanName);

}

操作类接口实现

@Service
@Slf4j
public class DefaultDyTaskManager implements DyTaskManager, CommandLineRunner, ApplicationContextAware {

    private ApplicationContext context;

    Map taskMap = new ConcurrentHashMap<>();

    @Autowired
    private ThreadPoolTaskScheduler taskScheduler;

    @Autowired
    private IDynamicTaskConfigService dynamicTaskConfigService;

    @Override
    public boolean cancelTask(String beanName) {
        if (StringUtils.isBlank(beanName)) {
            return false;
        }
        DyTaskInfo task = taskMap.remove(beanName);
        if (task != null && task.getFuture() != null) {
            task.getFuture().cancel(true);
            return true;
        }
        return false;
    }

    @Override
    public boolean runTask(String beanName) {
        DyTask target = null;
        try {
            target = (DyTask) context.getBean(beanName);
        }
        catch (Throwable e) {
            throw new ServiceException("无法获取bean信息, 无法执行任务:" + e.getMessage());
        }

        // 执行
        target.run();

        return true;
    }

    @Override
    public boolean scheduleTask(String beanName, String cron) {
        DyTask target = null;
        try {
            target = (DyTask) context.getBean(beanName);
        }
        catch (Throwable e) {
            throw new ServiceException("无法获取bean信息, 无法执行任务:" + e.getMessage());
        }

        Method method = null;
        try {
            method = target.getClass().getMethod("run");
        }
        catch (NoSuchMethodException e) {
            throw new ServiceException("无法获取run方法, 无法执行任务:" + e.getMessage());
        }

        try {
            CronTask cronTask = new CronTask(createRunnable(target, method),
                    new CronTrigger(cron, TimeZone.getTimeZone(ZoneId.systemDefault())));
            DyTaskInfo taskInfo = new DyTaskInfo(cronTask);
            ScheduledFuture future = taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
            taskInfo.setFuture(future);

            cancelTask(beanName);

            taskMap.put(beanName, taskInfo);

            return true;
        }
        catch (Throwable e) {
            log.info("配置异常:{}", e.getMessage());
        }

        return true;
    }

    private Runnable createRunnable(Object target, Method method) {
        Method invocableMethod = AopUtils.selectInvocableMethod(method, target.getClass());
        return new ScheduledMethodRunnable(target, invocableMethod);
    }

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

    @Override
    public void run(String... args) throws Exception {
        List taskConfigs = dynamicTaskConfigService.findAllByStatus(0);
        taskConfigs.forEach(config -> {
            if (StringUtils.isNotBlank(config.getBeanName()) && StringUtils.isNotBlank(config.getCron())) {
                log.info(">>> 初始化定时任务: {},{},{}", config.getName(), config.getBeanName(), config.getCron());
                try {
                    scheduleTask(config.getBeanName(), config.getCron());
                }
                catch (Throwable e) {
                    log.error("初始化失败: {}", e.getMessage());
                }
            }
        });
    }
}

 

你可能感兴趣的:(Java)