欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringTask实现定时任务

程序员文章站 2022-05-24 20:51:15
...

Spring task的三种典型的应用模式可以集成在传统springMVC项目,也可以在SpringBoot项目中,优点比较轻量,不需要添加过多依赖,缺点分布式支持不友好

不累赘叙述task的引用了,常用模式有:

1. 静态定时

直接使用@Scheduled注释,缺点cron表达的信息固定不可变

2. 修改定时器

import java.util.Date;

import org.apache.log4j.Logger;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@EnableScheduling
@RequestMapping("/task")
public class TaskController implements SchedulingConfigurer {

    private Logger logger = Logger.getLogger(TaskController.class);

    /**
     * 定时任务的定时器表达式: 秒 分 时 日期 月 星期
     * 注意:有的地方说定时正则表达式可以有year,即7个元素,但是,在spring-boot里面,只能是6个元素,没有年。
     */
    private String cronExpression = "1/5 * * * * *";

    /**
     * 通过REST API请求对参数进行修改,定时规则进行调整
     * @param exp
     * @return
     */
    @RequestMapping("/change")
    public String change(@RequestParam("exp") String exp) {
        cronExpression = exp;
        logger.info("new cron expression: " + exp);
        return cronExpression;
    }

    /**
     * 定时任务要执行的方法
     * @return
     */
    private Runnable getTask() {
        Runnable task = new Runnable() {
            @Override
            public void run() {
            	logger.info("==定时任务==开始: " + new Date());
            	
            	//业务处理,忽视所有异常
                try {
                	//do something
                	
				} catch (Exception e) {
					e.printStackTrace();
				}
                
                logger.info("==定时任务==结束: " + new Date());
            }
        };
        return task;
    }

    /**
     * 调度实现的时间控制
     * @param scheduledTaskRegistrar
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        Trigger trigger=new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                CronTrigger cronTrigger=new CronTrigger(cronExpression);
                return cronTrigger.nextExecutionTime(triggerContext);
            }
        };
        scheduledTaskRegistrar.addTriggerTask(getTask(), trigger);
    }
}

缺点:控制不强,没有持久化,不随时启动停止

3. 动态启动和停止以及修改定时规则

/**
 * 定时任务核心类
 * @ClassName: TimmerComponent
 */
@Component
public class TimmerComponent {

    // 保存任务
    private Map<String, ScheduledFuture<?>> futuresMap = new ConcurrentHashMap<String, ScheduledFuture<?>>();
    
    private Logger logger = Logger.getLogger(TimmerComponent.class);

	//持久化任务
    //@Autowired
    //private ITaskJobDao taskJobDao;
    
    // 创建ThreadPoolTaskScheduler线程池
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;
    
    @Bean
    public ThreadPoolTaskScheduler getThreadPoolTaskScheduler(){
    	threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
    	threadPoolTaskScheduler.setPoolSize(20);
    	threadPoolTaskScheduler.setThreadNamePrefix("task-");
    	threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
    	threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
    	threadPoolTaskScheduler.initialize();
        return threadPoolTaskScheduler;
    }

    // 初始化任务
    @Bean
    public Map<String, ScheduledFuture<?>> initTimmer(){
		//启动时获取持久化任务,可以避免服务重启任务丢失,如不需要可以注释
        // List<WelcomTaskJob> list = welcomTaskJobDao.getList4Enable();
        // for (WelcomTaskJob s : list){
            // ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(getRunnable(s), getTrigger(s));
            // futuresMap.put(s.getTaskJobCode(), future);
        // }
        return futuresMap;
    }
    

    /**
     * 添加任务
     * @param s
     */
    public void addTask(WelcomTaskJob s){
    	logger.info("定时任务#====>添加: " + new Date());
        ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(getRunnable(s), getTrigger(s));
        futuresMap.put(s.getTaskJobCode(), future);
    }

    /**
     * 暂停任务
     * @param key
     * @return
     */
    public boolean cancelTask(String key) {
    	logger.info("定时任务#====>取消: " + new Date());
        ScheduledFuture<?> toBeRemovedFuture = futuresMap.remove(key);
        if (toBeRemovedFuture != null) {
            toBeRemovedFuture.cancel(true);
            return true;
        } else {
            return false;
        }
    }

    /**
     * 更新任务
     * @param s
     */
    public void updateTask(WelcomTaskJob s) {
    	logger.info("定时任务#====>更新: " + new Date());
        ScheduledFuture<?> toBeRemovedFuture = futuresMap.remove(s.getTaskJobCode());
        if (toBeRemovedFuture != null) {
            toBeRemovedFuture.cancel(true);
        }
        ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(getRunnable(s), getTrigger(s));
        futuresMap.put(s.getTaskJobCode(), future);
    }


    /**
     * 转换首字母小写
     *
     * @param str
     * @return
     */
    public static String lowerFirstCapse(String str) {
        char[] chars = str.toCharArray();
        chars[0] += 32;
        return String.valueOf(chars);
    }

    /**
     * runnable
     * @param taskJob
     * @return
     */
    private Runnable getRunnable(WelcomTaskJob taskJob){
        return new Runnable() {
            @Override
            public void run() {
                Class<?> clazz;
                try {
                	logger.info("定时任务#====>启动: " + new Date());
					//使用反射原理来获取执行操作类及方法,注意可能无法获取登录用户信息,业务操作中请勿绑定
                    clazz = Class.forName(taskJob.getClassName());
                    String className = lowerFirstCapse(clazz.getSimpleName());
                    Object bean = (Object) ApplicationContextHelper.getBean(className);
                    Method method = ReflectionUtils.findMethod(bean.getClass(), taskJob.getMethodName());
                    ReflectionUtils.invokeMethod(method, bean);
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                }
            }
        };
    }

    /**
     * Trigger
     * @param taskJob
     * @return
     */
    private Trigger getTrigger(WelcomTaskJob taskJob){
        return new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                CronTrigger trigger = new CronTrigger(taskJob.getCron());
                Date nextExec = trigger.nextExecutionTime(triggerContext);
                return nextExec;
            }
        };

    }
}
/**
 * 获取bean
 * @ClassName: ApplicationContextHelper
 */
@Component
public class ApplicationContextHelper implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public ApplicationContextHelper() {
    }

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

    public static Object getBean(String beanName) {
        return applicationContext != null?applicationContext.getBean(beanName):null;
    }
}

 

 

参考 : https://www.cnblogs.com/shihuc/p/9275780.html

            https://blog.csdn.net/xcc_2269861428/article/details/100023788