springboot學習(二十五) 使用springboot執行動態任務

可以使用quartz等任務框架實現動態任務,但其實spring本身就支持

springboot簡單定時任務執行方式:

@Configuration      
@EnableScheduling   
public class SaticScheduleTask {
    //添加定時任務
    @Scheduled(cron = "0/5 * * * * ?")
    //或直接指定時間間隔,例如:5
    //@Scheduled(fixedRate=5000)
    private void configureTasks() {
        System.err.println("執行定時任務: " + LocalDateTime.now());
    }
}

動態定時任務就複雜一些。但功能強大

1、編寫定時任務配置類

package com.iscas.biz.schedule;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

/**
 * 定時任務配置類
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2020/2/25 18:14
 * @since jdk1.8
 */
@Configuration
public class SchedulingConfig {
    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 定時任務執行線程池核心線程數
        taskScheduler.setPoolSize(2);
        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
        return taskScheduler;
    }
}

2、編寫定時任務註冊類

package com.iscas.biz.schedule;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 定時任務註冊類
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2020/2/25 18:15
 * @since jdk1.8
 */
@Component
public class CronTaskRegister implements DisposableBean {

    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);

    @Autowired
    private TaskScheduler taskScheduler;

    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }

    /**
     * 新增定時任務
     * @param task
     * @param cronExpression
     */
    public void addCronTask(Runnable task, String cronExpression) {
        addCronTask(new CronTask(task, cronExpression));
    }

    public void addCronTask(CronTask cronTask) {
        if (cronTask != null) {
            Runnable task = cronTask.getRunnable();
            if (this.scheduledTasks.containsKey(task)) {
                removeCronTask(task);
            }

            this.scheduledTasks.put(task, scheduleCronTask(cronTask));
        }
    }

    /**
     * 移除定時任務
     * @param task
     */
    public void removeCronTask(Runnable task) {
        ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
        if (scheduledTask != null) {
            scheduledTask.cancel();
        }
    }

    public ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask();
        scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());

        return scheduledTask;
    }


    @Override
    public void destroy() {
        for (ScheduledTask task : this.scheduledTasks.values()) {
            task.cancel();
        }
        this.scheduledTasks.clear();
    }
}

3、編寫定時任務執行類

package com.iscas.biz.schedule;

import com.iscas.base.biz.service.common.SpringService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * 定時任務執行類
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2020/2/25 18:16
 * @since jdk1.8
 */
public class SchedulingRunnable implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);

    private String beanName;

    private String methodName;

    private Object[] params;

    public SchedulingRunnable(String beanName, String methodName) {
        this(beanName, methodName, null);
    }

    public SchedulingRunnable(String beanName, String methodName, Object...params ) {
        this.beanName = beanName;
        this.methodName = methodName;
        this.params = params;
    }

    @Override
    public void run() {
        logger.info("定時任務開始執行 - bean:{},方法:{},參數:{}", beanName, methodName, params);
        long startTime = System.currentTimeMillis();

        try {
            Object target = SpringService.getBean(beanName);

            Method method = null;
            if (null != params && params.length > 0) {
                Class<?>[] paramCls = new Class[params.length];
                for (int i = 0; i < params.length; i++) {
                    paramCls[i] = params[i].getClass();
                }
                method = target.getClass().getDeclaredMethod(methodName, paramCls);
            } else {
                method = target.getClass().getDeclaredMethod(methodName);
            }

            ReflectionUtils.makeAccessible(method);
            if (null != params && params.length > 0) {
                method.invoke(target, params);
            } else {
                method.invoke(target);
            }
        } catch (Exception ex) {
            logger.error(String.format("定時任務執行異常 - bean:%s,方法:%s,參數:%s ", beanName, methodName, params), ex);
        }

        long times = System.currentTimeMillis() - startTime;
        logger.info("定時任務執行結束 - bean:{},方法:{},參數:{},耗時:{} 毫秒", beanName, methodName, params, times);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        SchedulingRunnable that = (SchedulingRunnable) o;
        if (params == null) {
            return beanName.equals(that.beanName) &&
                    methodName.equals(that.methodName) &&
                    that.params == null;
        }

        return beanName.equals(that.beanName) &&
                methodName.equals(that.methodName) &&
                params.equals(that.params);
    }

    @Override
    public int hashCode() {
        if (params == null) {
            return Objects.hash(beanName, methodName);
        }

        return Objects.hash(beanName, methodName, params);
    }
}

4、編寫定時任務控制類

package com.iscas.biz.schedule;

import java.util.concurrent.ScheduledFuture;

/**
 * 定時任務控制類
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2020/2/25 18:18
 * @since jdk1.8
 */
public final class ScheduledTask {

    public volatile ScheduledFuture<?> future;
    /**
     * 取消定時任務
     */
    public void cancel() {
        ScheduledFuture<?> future = this.future;
        if (future != null) {
            future.cancel(true);
        }
    }
}

5、測試
編寫一個任務執行類和執行函數

package com.iscas.biz.schedule;

import com.iscas.base.biz.config.Constants;
import com.iscas.base.biz.model.EquipSubscribeVO;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.simp.user.SimpUser;
import org.springframework.messaging.simp.user.SimpUserRegistry;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;

/**
 * 編寫一個任務類和執行函數
 *
 * @author zhuquanwen
 * @vesion 1.0
 * @date 2020/2/25 18:31
 * @since jdk1.8
 */
@Component("equipSubscribeClearTask")
public class EquipSubscribeClearTask {
    @Autowired
    private SimpUserRegistry userRegistry;
    /**
     * 清理訂閱的subscribe
     * */
    public void clearEquipSubscribe() { 
        Set<SimpUser> users = userRegistry.getUsers();
        Map<String, List<EquipSubscribeVO>> subscribeQuip = Constants.SUBSCRIBE_QUIP;
        Set<String> keys = Constants.SUBSCRIBE_QUIP.keySet();
        if (CollectionUtils.isNotEmpty(keys)) {
            for (String username : keys) {
                if (CollectionUtils.isNotEmpty(users)) {
                    boolean flag = false;
                    for (SimpUser user : users) {
                        String name = user.getName();
                        if (Objects.equals(username, name)) {
                            flag = true;
                            break;
                        }
                    }
                    if (!flag) {
                        //清除
                        Constants.SUBSCRIBE_QUIP.remove(username);
                    }
                }
             }
        }
    }
}

使用spring調用

 CronTaskRegister cronTaskRegister = applicationContext.getBean(CronTaskRegister.class);
        //定時清理硬件屬性訂閱
        SchedulingRunnable task = new SchedulingRunnable("equipSubscribeClearTask", "clearEquipSubscribe", null);
        //30S執行一次任務
        cronTaskRegister.addCronTask(task, "0/30 * * * * ?");

執行結果在控制檯打印

2020-02-25 18:39:00.000 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:41  - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:39:03.076 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:69  - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:3076 毫秒
2020-02-25 18:39:30.000 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:41  - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:47:17.137 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:69  - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:467137 毫秒
2020-02-25 18:47:30.001 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:41  - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:47:33.494 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:69  - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:3492 毫秒
2020-02-25 18:48:00.001 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:41  - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:48:00.001 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:69  - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:0 毫秒
2020-02-25 18:48:30.000 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:41  - 定時任務開始執行 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null
2020-02-25 18:48:30.000 INFO  com.iscas.biz.schedule.SchedulingRunnable Line:69  - 定時任務執行結束 - bean:equipSubscribeClearTask,方法:clearEquipSubscribe,參數:null,耗時:0 毫秒
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章