Spring定时任务基于注解的学习

前言


关于相关定时任务的开发工具一般用到quartzSpring Task两种方式。
关于quartz的配置相对要复杂一些,具体请看我之前的认识quartz定时器
Spring Task更为广泛使用,非常轻量级配置简单,使用方便。


一、相关配置

spring的配置文件applicationContext.xml中配置。

1、在xmlns中添加:

xmlns:task="http://www.springframework.org/schema/task" 

这里写图片描述
2、在xsi:schemaLocation中添加:

http://www.springframework.org/schema/task    
http://www.springframework.org/schema/task/spring-task-3.1.xsd

这里写图片描述
3、增加注解驱动及扫描包配置
这里写图片描述

<task:annotation-driven/>
<!--扫描的是定时任务存放的包位置-->
<context:component-scan base-package="com.how2java.controller.base" />

二、实现简单定时任务

1、在确保扫描包能扫描能正确扫描的前提下,在扫描包下创建interface TaskConfig接口:

public interface TaskConfig {
    public void task();
}

2、实现接口任务TaskAconfigTaskBconfig

//@EnableScheduling   //该注解功能可以替代spring中<task:annotation-driven/>驱动配置
@Component
public class TaskAConfig implements TaskConfig{

    private static final Logger logger = LogManager.getLogger(TaskAConfig.class);

    @Scheduled(cron="0/5 * * * * ?") //每5m执行一次
     public void task(){ 
        logger.info("任务A执行......");
     }
}
//@EnableScheduling   //该注解功能可以替代spring中<task:annotation-driven/>驱动配置
@Component
public class TaskBConfig implements TaskConfig{

    private static final Logger logger = LogManager.getLogger(TaskBConfig.class);

    @Scheduled(cron="0/10 * * * * ?") //每10m执行一次
     public void task(){ 
        logger.info("任务B执行......");
     }
}
  • 定时任务方法中不能有返回值,即public void task()不能有返回值,如果需要查看返回值,可以利用日志来进行查看。
  • @EnableScheduling注解:可以代替该注解功能可以替代spring配置文件中<task:annotation-driven/>任务驱动配置。也就是不需要在applicationContext.xml中添加<task:annotation-driven/>
  • cron的时间表达式一般有至少6个(可能也会7个)有空格分隔的时间元素。

1.秒(0~59)
2.分钟(0~59)
3.小时(0~23)
4.天(月)(0~31,但是你需要考虑你月的天数)
5.月(0~11)
6.天(星期)(1~7 或SUN ,MON,TUE,WED,THU,FRI,SAT)
7.年份(1970-2099)

每个元素可以是:

一个值(如6)
一个连续区间(9-12)
一个间隔时间(8-18/4)(/表示每隔4小时)
一个列表(1,3,5)
通配符:由于”月份中的日期”和”星期中的日期”这两个元素互斥的,必须要对其中一个设置?.

举例:

扫描二维码关注公众号,回复: 358323 查看本文章

0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
0 15 10 * * ? 每天上午10:15触发
0 15 10 ? * 6L 每月的最后一个星期五上午10:15触发
0 15 10 ? * 6#3 每月的第三个星期五上午10:15触发
0 10,44 14 ? 3 WED 每年三月的星期三的下午2:10和2:44触发

  • applicationContext.xml中没有配置线程池的话,定时任务默认的是单线程。
    如图,任务AB都执行,都属于默认的线程pool-1-thread-1
    这里写图片描述

三、实现多线程定时任务

由上可知,定时任务默认的单线程。对于简单的业务来说是没问题的,但是要实现多线程下较复杂的定时任务就需要配置多线程任务,其配置过程也十分简单。

首先,我们先看下默认的单线程定时任务:

业务要求:
任务A 5m 执行一次,但是sleep拖后10m执行即15m 执行一次,
任务B 10m 执行一次

@Component
public class TaskAConfig implements TaskConfig{

    private static final Logger logger = LogManager.getLogger(TaskAConfig.class);

    @Scheduled(cron="0/5 * * * * ?") //每5m执行一次
     public void task(){ 
        try {
            Thread.sleep(10000);//我们的业务是要求任务A先sleep 10m之后执行
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        logger.info("任务A执行......");
     }
}
@Component
public class TaskBConfig implements TaskConfig{

    private static final Logger logger = LogManager.getLogger(TaskBConfig.class);

    @Scheduled(cron="0/10 * * * * ?") //每10m执行一次
     public void task(){ 
        logger.info("任务B执行......");
     }
}

但是执行的结果是明明任务B每隔10m执行,现在变成了跟任务A一样15m执行一次,被拖后了5m,这样是不符合业务需求的。
这里写图片描述
接下里是多线程的实现:
applicationContext.xml配置线程池即可完美实现多线程

<task:annotation-driven scheduler="myScheduler"/>
<!-- 配置定时任务线程池 -->
<task:scheduler id="myScheduler" pool-size="5"/>  

执行结果如图,任务B不会被拖后,即任务A与任务B不再属于同一个线程,而是在线程池中不同的线程。
这里写图片描述

猜你喜欢

转载自blog.csdn.net/mynewclass/article/details/80164058