Springboot写定时任务《Springboot学习八》

版权声明:本文为HCG原创文章,未经博主允许不得转载。请联系[email protected] https://blog.csdn.net/qq_39455116/article/details/83744827

spring boot集成定时任务

//看之前本博客是有项目地址的:
https://github.com/HouChenggong/springboot_schedule

项目地址: 传送门

定时任务或者说定时调度,是系统中比较普遍的一个功能,例如数据归档、清理,数据定时同步(非实时),定时收发,流量控制等等都需要用到定时任务,常见的定时调度框架有Quartz、TBSchedule等。

同样,Spring自3.0版本起也增加了任务调度功能Schedule,它好比是一个轻量级的Quartz,使用起来方便、简洁,且不需要依赖其他的JAR包。之所以说它是轻量级Quartz,是因为在现如今遍地分布式的大环境下,Spring自带的Schedule不支持分布式部署,所以若是分布式环境开发请忽略此文章,可以选用Quartz、TBSchedule等,且一般稍大点的公司都有独立的统一调度中心。

开始配置

1. 启动类添加定时任务注解
@EnableScheduling
@SpringBootApplication
//@MapperScan("com.pf.org.cms.mapper")
public class CmsApplication {

    public static void main(String[] args) {
        SpringApplication.run(CmsApplication.class, args);
    }
}
2. 编写配置类

编写具体的定时任务组件(@Component注解),并且在需要定时调度的方法上添加@Scheduled触发器。Spring实现了Quartz简单的和cron表达式两种触发方式,这里我们用cron表达式,”0/20 * * * * ?”表示每20秒触发一次,具体cron表达式逻辑可以自行百度。

@Component
public class MyStaticTask {

    /**
     * 固定cron配置定时任务
     */
    @Scheduled(cron = "0/20 * * * * ?")
    public void doTask(){
        System.out.println("执行了MyStaticTask,时间为:"+new Date(System.currentTimeMillis()));
    }
}
 

以上,一个简单的定时任务便已完成,重新启动项目,你就会发现定时器了。

但是触发器是硬编码,相信肯定满足不了绝大部分业务场景,同样Spring提供了SchedulingConfigurer接口,下面介绍可配置、动态修改触发器的定时任务。


多线程定时任务

@Component
public class MyDynamicTask implements SchedulingConfigurer {
    private static Logger log = LoggerFactory.getLogger(MyDynamicTask.class);

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        //设定一个长度10的定时任务线程池
        //所有的定时任务都放在一个线程池中,定时任务启动时使用不同都线程。
        scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
    }

多线程定时任务结果日志

可以发现下面的定时任务都在任务池中,pool-1-thread-4、pool-1-thread-3、pool-1-thread-2

2018-11-05 11:55:00 284841 [pool-1-thread-4] INFO  c.p.o.c.configuration.MyStaticTask - 定时任务1 开始执行... 
2018-11-05 11:55:00 284841 [pool-1-thread-3] INFO  c.p.o.c.configuration.MyStaticTask - 定时任务2 开始执行... 
2018-11-05 11:55:00 284841 [pool-1-thread-1] INFO  c.p.o.c.configuration.MyStaticTask - 定时任务0:执行了MyStaticTask,时间为:Mon Nov 05 11:55:00 CST 2018 
2018-11-05 11:55:00 284841 [pool-1-thread-2] INFO  c.p.o.c.configuration.MyDynamicTask - 执行了MyDynamicTask,时间为:Mon Nov 05 11:55:00 CST 2018 

可配置的定时任务组件需要实现SchedulingConfigurer接口中的configureTasks方法,该方法有两个入参(Runnable task, Trigger trigger),第一个为我们任务的具体逻辑实现,第二个为触发器,动态的定时任务则意味着Trigger需要动态获取,由于之前我们已经集成redis,因此这里我们从redis获取相关配置。

//是从redis里面取数据,没有安装redis的可以参考这篇文章
。。。。

String newCron = redisManager.getStr("cms:MyDynamicTask");
package com.pf.org.cms.configuration;

import com.alibaba.druid.util.StringUtils;
import com.pf.org.cms.exception.CmsException;
import com.pf.org.cms.manage.RedisManager;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
public class MyDynamicTask implements SchedulingConfigurer {
    private static Logger log = LoggerFactory.getLogger(MyDynamicTask.class);

    @Autowired
    RedisManager redisManager;

    private static String cron;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(doTask(), getTrigger());
    }

    private Runnable doTask() {
        return new Runnable() {
            @Override
            public void run() {
                // 业务逻辑
                log.info("执行了MyDynamicTask,时间为:" + new Date(System.currentTimeMillis()));
            }
        };
    }

    private Trigger getTrigger() {
        return new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                // 触发器
                CronTrigger trigger = new CronTrigger(getCron());
                return trigger.nextExecutionTime(triggerContext);
            }
        };
    }

    public String getCron() {
        String newCron = redisManager.getStr("cms:MyDynamicTask");
        if (StringUtils.isEmpty(newCron)) {
            throw new CmsException("The config cron expression is empty");
        }
        if (!newCron.equals(cron)) {
            log.info(new StringBuffer("Cron has been changed to:'").append(newCron).append("'. Old cron was:'").append(cron).append("'").toString());
            cron = newCron;
        }
        return cron;
    }
}


安装redis并在redis的db2数据库中添加了

key:cms:MyDynamicTask
value:abcDEF

之后发生了如下的错误

Cron expression must consist of 6 fields

原因呢:其实就是你的value里面要是定时器的语法,我们的自定义语句中其实就是去redis里面去字符串,这个字符串是定时器脚本,而不是任意的这里贴出我的脚本,其实和最初的脚本一样

key:cms:MyDynamicTask
value:0/20 * * * * ?
项目地址:

https://github.com/HouChenggong/springboot_schedule

猜你喜欢

转载自blog.csdn.net/qq_39455116/article/details/83744827