定时任务在日常开发过程中非常常见,而且在日常的项目开发中也有多种实现方式,而且做任务调度的框架有很多种,小编最近的感受,如果想真正使用好任务调度还是存在困难的,所以分步学习,逐个击破!在这篇文章小编主要写spring中Scheduled。

spring定时任务设置有两种方式,注解和xml配置。推荐使用注解,在本文章也主要介绍注解方式配置。

注解方式配置定时任务

下面的步骤默认spring的其他配置项都已经配置好(比如启动注解配置,包路径扫描等)

1:在spring配置文件中配置,添加命名空间

  • xmlns添加:
xmlns:task="http://www.springframework.org/schema/task"
  • xsi:schemaLocation添加

    • 注意"4.3"这是版本号,要修改和你的其他xsd版本号一致
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd"
  • 启动注解驱动

    • 注意“dataScheduler”为自定义名称,可以通过自己的业务定义 合适 的名称
<task:annotation-driven scheduler="dataScheduler"/>
  • 开启任务调度器,并配置线程池大小

    • 注意此处的id指定的就是上面的自定义名称
    • spring的任务调度默认是单线程的,如果你的项目会有多任务定时执行,并且执行时间会相交的话,应该根据任务的具体执行情况配置线程池大小
    • 如果不配置线程池,并且A和B任务在同一时间执行,A先执行的话,B要等待A执行完才可以执行,AB不会同时执行
<task:scheduler id="dataScheduler" pool-size="5"/>

2:使用注解配置定时任务

  • 在你需要配置定时任务的方法上使用注解@Scheduled即可,下面一个简单案例:

    • 注意 下面的案例是在每天的早上2点执行
    • “0 0 2 * * *”是怎么组合的?下面会详细介绍@Scheduled()注解
@Scheduled(cron = "0 0 2 * * *")
public void init(){todo...
}

在此需要注意:@Scheduled只能注释在无参的方法上,我看网上有许多博客说必须无参无返回值的,但是经过我的测试有返回值是可以的,可能是版本更新了吧。

@Scheduled

@Scheduled注解是Spring专门为定时任务设计的注解

首先,让我们来看看这个注解是怎么组成的吧(适用于版本JDK8与spring4.3及其以上)

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {String cron() default "";String zone() default "";long fixedDelay() default -1L;String fixedDelayString() default "";long fixedRate() default -1L;String fixedRateString() default "";long initialDelay() default -1L;String initialDelayString() default "";
}

从上述代码中看以看出:

1:@Scheduled被注解部分:

  • 元注解@Target表明@Scheduled注解可以在方法上使用(ElementType.METHOD),也可以作为元注解对其他注解进行注解(ElementType.ANNOTATION_TYPE)
  • 元注解@Retention表明此注解会被JVM所保留,也就是会保存在运行时(RetentionPolicy.RUNTIME)
  • 元注解@Documented表明此注解应该被 javadoc工具记录。默认情况下javadoc是不包括注解的。
  • JDK8添加的注解@Repeatable表明此注解可以在同一个地方被重复使用

上述的所涉及到的注解有不清楚作用的,可以自行baidu\google,网上有好多介绍的文章。

2:@Scheduled参数部分,总共包含8各部分,我们来分别看一下其作用:

  • cron:一个类似cron的表达式,扩展了通常的UN * X定义,包括秒,分,时,星期,月,年的触发器。
  • fixedDelay:在最后一次调用结束和下一次调用开始之间以固定周期(以毫秒为单位)执行带注释的方法。(要等待上次任务完成后)
  • fixedDelayString:同上面作用一样,只是String类型
  • fixedRate:在调用之间以固定的周期(以毫秒为单位)执行带注释的方法。(不需要等待上次任务完成)
  • fixedRateString:同上面作用一样,只是String类型
  • initialDelay:第一次执行fixedRate()或fixedDelay()任务之前延迟的毫秒数 。
  • initialDelayString:同上面作用一样,只是String类型
  • zone:指明解析cron表达式的时区。

cron可以组合出更多的定时情况,fixedDelay和fixedRate只能定义每隔多长时间执行一次。

在上述cron、fixedDelay、fixedRate 只能同时存在一个,使用其中一个就不能使用另外的一个,否则会报错“java.lang.IllegalStateException”

原理简介

1:主要过程:

  1. spring在使用applicationContext将类全部初始化。
  2. 调用ScheduledAnnotationBeanPostProcessor类中的postProcessAfterInitialization方法获取项目中所有被注解 @Scheduled注解的方法 。
  3. 通过processScheduled方法将所有定时的方法存放在Set tasks = new LinkedHashSet(4); 定时任务队列中,并解析相应的参数。顺序存放,任务也是顺序执行。存放顺序为cron>fixedDelay>fixedRate
  4. 将解析参数后的定时任务存放在一个初始容量为16 的map中,key为bean name,value为定时任务:private final Map<Object, Set> scheduledTasks = new IdentityHashMap(16);
  5. 之后交给ScheduledTaskRegistrar类的方法scheduleTasks去添加定时任务。

2:上述就是一个大致过程,下面看一下相应的源码:

注意 :spring对定时任务的操作的源码全部在spring-context.jar包下的org.springframework.scheduling包下面,主要包含三部分:annotation、config、 support,大家有兴趣的话可以去看看

1:获取项目中所有被注解 @Scheduled注解的方法

public Object postProcessAfterInitialization(Object bean, String beanName) {Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean);if (!this.nonAnnotatedClasses.contains(targetClass)) {Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, new MetadataLookup<Set<Scheduled>>() {public Set<Scheduled> inspect(Method method) {//获取注解方法**Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, Scheduled.class, Schedules.class);**return !scheduledMethods.isEmpty() ? scheduledMethods : null;}});if (annotatedMethods.isEmpty()) {...} else {Iterator var5 = annotatedMethods.entrySet().iterator();while(var5.hasNext()) {Entry<Method, Set<Scheduled>> entry = (Entry)var5.next();Method method = (Method)entry.getKey();Iterator var8 = ((Set)entry.getValue()).iterator();while(var8.hasNext()) {Scheduled scheduled = (Scheduled)var8.next();//将获取的任务进行参数解析并存放到任务队列this.processScheduled(scheduled, method, bean);}}...}}return bean;
}

2:通过processScheduled方法将所有定时的方法存放在定时任务队列中

protected void processScheduled(Scheduled scheduled, Method method, Object bean) {try {...//解析initialDelayString参数String initialDelayString = scheduled.initialDelayString();if (StringUtils.hasText(initialDelayString)) {...}//解析cron参数String cron = scheduled.cron();if (StringUtils.hasText(cron)) {...//存放到任务队列中tasks.add(this.registrar.scheduleCronTask(new CronTask(runnable, new CronTrigger(cron, timeZone))));}...//解析fixedDelay参数long fixedDelay = scheduled.fixedDelay();if (fixedDelay >= 0L) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;tasks.add(this.registrar.scheduleFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay)));}String fixedDelayString = scheduled.fixedDelayString();if (StringUtils.hasText(fixedDelayString)) {...//存放到任务队列中tasks.add(this.registrar.scheduleFixedDelayTask(new IntervalTask(runnable, fixedDelay, initialDelay)));}//解析fixedRate参数long fixedRate = scheduled.fixedRate();if (fixedRate >= 0L) {Assert.isTrue(!processedSchedule, errorMessage);processedSchedule = true;tasks.add(this.registrar.scheduleFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)));}String fixedRateString = scheduled.fixedRateString();if (StringUtils.hasText(fixedRateString)) {...//存放到任务队列中tasks.add(this.registrar.scheduleFixedRateTask(new IntervalTask(runnable, fixedRate, initialDelay)));}Assert.isTrue(processedSchedule, errorMessage);Map var19 = this.scheduledTasks;//并发控制并将任务存放在map中synchronized(this.scheduledTasks) {Set<ScheduledTask> registeredTasks = (Set)this.scheduledTasks.get(bean);if (registeredTasks == null) {registeredTasks = new LinkedHashSet(4);//将任务存放在map中this.scheduledTasks.put(bean, registeredTasks);}((Set)registeredTasks).addAll(tasks);}} catch (IllegalArgumentException var26) {throw new IllegalStateException("Encountered invalid @Scheduled method '" + method.getName() + "': " + var26.getMessage());}
}

3:之后交给ScheduledTaskRegistrar类的方法scheduleTasks去添加定时任务

protected void scheduleTasks() {if (this.taskScheduler == null) {this.localExecutor = Executors.newSingleThreadScheduledExecutor();this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);}Iterator var1;if (this.triggerTasks != null) {var1 = this.triggerTasks.iterator();while(var1.hasNext()) {TriggerTask task = (TriggerTask)var1.next();this.addScheduledTask(this.scheduleTriggerTask(task));}}if (this.cronTasks != null) {var1 = this.cronTasks.iterator();while(var1.hasNext()) {CronTask task = (CronTask)var1.next();this.addScheduledTask(this.scheduleCronTask(task));}}IntervalTask task;if (this.fixedRateTasks != null) {var1 = this.fixedRateTasks.iterator();while(var1.hasNext()) {task = (IntervalTask)var1.next();this.addScheduledTask(this.scheduleFixedRateTask(task));}}if (this.fixedDelayTasks != null) {var1 = this.fixedDelayTasks.iterator();while(var1.hasNext()) {task = (IntervalTask)var1.next();this.addScheduledTask(this.scheduleFixedDelayTask(task));}}
}

此部分只是对原理进行了简单的介绍,如果有兴趣深入了解,可以去看看源码~

其他

做定时任务还可以使用java自带的原生API,Timer和TimerTask去设计。

  • Timer:一种工具,线程用其安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
  • TimerTask:定义一个被执行的任务,Timer 安排该任务为一次执行或重复执行的任务。

可以这样理解Timer是一种定时器工具,用来在一个后台线程计划执行指定任务,而TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。

这里就简单的提一下,并不是本文的重点,具体的用法自行google吧~

【定时任务】——Spring定时任务Scheduled相关推荐

  1. Spring 的@Scheduled注解实现定时任务运行和调度

    Spring 的@Scheduled注解实现定时任务运行和调度 首先要配置我们的spring.xml   ---  即spring的主配置文件(有的项目中叫做applicationContext.xm ...

  2. java 注解scheduler_使用spring的@Scheduled注解执行定时任务,启动项目不输出警告

    在applicationContext.xml中添加: xmlns:task="http://www.springframework.org/schema/task" xsi:sc ...

  3. Spring的@Scheduled注解实现定时任务

    Spring的@Scheduled注解实现定时任务 [简介篇] 项目经常会用到定时任务,实现定时任务的方式有很多种.在Spring框架中,实现定时任务很简单,常用的实现方式是使用注解@Schedule ...

  4. Spring定时任务@scheduled多线程的使用(@Async注解)

    1.开篇 在Spring定时任务@Scheduled注解使用方式浅窥这篇文章里面提及过,spring的定时任务默认是单线程的,他在某些场景下会造成堵塞,那么如果我们想让每一个任务都起一条线程去执行呢? ...

  5. Spring定时任务-@Scheduled

    目的:使用Spring的@Scheduled实现定时任务 1.在spring的配置文件中加入以下配置: xmlns:task="http://www.springframework.org/ ...

  6. Spring定时任务scheduled

    Spring定时任务 一. cron 表达式 ​ 1. 概念:Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式: ​ 2. Cro ...

  7. spring定时任务(Scheduled)运行阻塞不执行/Redission分布式锁阻塞问题

    spring定时任务(Scheduled)运行阻塞不执行/Redission分布式锁阻塞问题 最近项目中发现一个bug,排查了很久,最后发现问题所在,在此记录一下. 问题描述: 项目运行一段时间后,c ...

  8. spring定时任务Scheduled与定时任务线程池配置SchedulingConfigurer ,Java

    spring定时任务Scheduled与定时任务线程池配置SchedulingConfigurer ,Java spring默认定时任务的使用 package zhangphil.demo;impor ...

  9. Spring定时任务@Scheduled注解使用方式浅窥(cron表达式、fixedRate和fixedDelay)

    1.开篇 spring的@Scheduled定时任务相信大家都是十分熟悉.最近在使用过程中发现了一些问题,写篇文章,和大家分享一下.结论在最后,不想看冗长过程的小伙伴可以直接拉到最后看结论. 2.简单 ...

最新文章

  1. 利用蒙特卡罗法,国外老哥成功制造出 100% 投篮命中的篮板!
  2. 从投票应用说起,功能才不是轻社交App的核心呢!
  3. 【Unity】2.11 了解游戏有哪些分类对你开阔思路有好处
  4. RHEL5中YUM命令解决RPM包依赖性
  5. Spring Boot程序无法加载主类解决方法
  6. 蓝昭餐饮管理系统服务器无法连接,服务器安全加固操作指南.docx
  7. 2018,广东,深圳马峦山游玩攻略(含登山线路)
  8. Linux-pthread如何设置线程的优先级
  9. SpringBoot实战(十四):Spring Boot Admin 集成安全模块
  10. 【chrome插件】web版微信接入图灵机器人API实现自动回复
  11. 今天给同学写5个数据结构算法的题...感觉很有价值的几个题..感兴趣的坐下。。...
  12. 数字媒体声音设计 第一章 概述
  13. MAC wps中选中的页面和缩放打印
  14. execute immediate
  15. 测试几个免费在线音乐识别器
  16. OA系统中如何实现合同管理?
  17. 【ValueError: could not convert string to float: ‘young‘】python利用pandas对string类型的数据序列化
  18. Pr:Lumetri范围
  19. 羊le个羊 小游戏 简单源码开源 思路分析
  20. b2c项目基础架构分析(一)b2c 大型站点方案简述 已补充名词解释

热门文章

  1. vue+swiper仿抖音视频滑动
  2. w ndows只能安装到gpt磁盘,Windows 只能安装到 GPT 磁盘什么意思
  3. 网易 天下2 的简单评论
  4. java获取本机IP,系统随机分配端口号,获取当前线程ID
  5. 局域网共享hfs 软件使用
  6. Asp.Net Ajax Control Toolkit 服务器端控件
  7. 漏斗分析(Funnel Analysis)
  8. 松灵机器人二次开发之一
  9. 1.什么是 ZooKeeper「第一章 基础入门」「架构之路ZooKeeper理论和实战」
  10. 深户居民可一签多行香港 公务员暂不享受