点击上方“方志朋”,选择“设为星标”

回复”666“获取新整理的面试资料

作者:静默虚空

https://github.com/dunwu/spring-tutorial

概述

如果想在Spring中使用任务调度功能,除了集成调度框架Quartz这种方式,也可以使用Spring自己的调度任务框架。

使用Spring的调度框架,优点是:支持注解@Scheduler,可以省去大量的配置。

实时触发调度任务

TaskScheduler接口

Spring3引入了TaskScheduler接口,这个接口定义了调度任务的抽象方法。

TaskScheduler接口的声明:

public interface TaskScheduler {ScheduledFuture schedule(Runnable task, Trigger trigger);ScheduledFuture schedule(Runnable task, Date startTime);ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);ScheduledFuture scheduleAtFixedRate(Runnable task, long period);ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);}

从以上方法可以看出TaskScheduler有两类重要参数:

  • 一个是要调度的方法,即一个实现了Runnable接口的线程类的run()方法;

  • 另一个就是触发条件。

TaskScheduler接口的实现类

它有三个实现类:DefaultManagedTaskSchedulerThreadPoolTaskSchedulerTimerManagerTaskScheduler

  • DefaultManagedTaskScheduler:基于JNDI的调度器。

  • TimerManagerTaskScheduler:托管commonj.timers.TimerManager实例的调度器

  • ThreadPoolTaskScheduler:提供线程池管理的调度器,它也实现了TaskExecutor接口,从而使的单一的实例可以尽可能快地异步执行。

Trigger接口

Trigger接口抽象了触发条件的方法。

Trigger接口的声明:

public interface Trigger {Date nextExecutionTime(TriggerContext triggerContext);
}

Trigger接口的实现类

CronTrigger:实现了cron规则的触发器类(和Quartz的cron规则相同)。

PeriodicTrigger:实现了一个周期性规则的触发器类(例如:定义触发起始时间、间隔时间等)。

完整范例

实现一个调度任务的功能有以下几个关键点:

(1) 定义调度器

在spring-bean.xml中进行配置

使用task:scheduler标签定义一个大小为10的线程池调度器,spring会实例化一个ThreadPoolTaskScheduler

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc"xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.1.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task-3.1.xsd"><mvc:annotation-driven/><task:scheduler id="myScheduler" pool-size="10"/>
</beans>

注:不要忘记引入xsd:

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

(2) 定义调度任务

定义实现Runnable接口的线程类。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class DemoTask implements Runnable {final Logger logger = LoggerFactory.getLogger(this.getClass());@Overridepublic void run() {logger.info("call DemoTask.run");}
}

(3) 装配调度器,并执行调度任务

在一个Controller类中用@Autowired注解装配TaskScheduler

然后调动TaskScheduler对象的schedule方法启动调度器,就可以执行调度任务了。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;@Controller
@RequestMapping("/scheduler")
public class SchedulerController {   @AutowiredTaskScheduler scheduler;@RequestMapping(value = "/start", method = RequestMethod.POST)public void start() {scheduler.schedule(new DemoTask(), new CronTrigger("0/5 * * * * *"));}
}

访问/scheduler/start接口,启动调度器,可以看到如下日志内容:

13:53:15.010 myScheduler-1 o.zp.notes.spring.scheduler.DemoTask.run - call DemoTask.run
13:53:20.003 myScheduler-1 o.zp.notes.spring.scheduler.DemoTask.run - call DemoTask.run
13:53:25.004 myScheduler-2 o.zp.notes.spring.scheduler.DemoTask.run - call DemoTask.run
13:53:30.005 myScheduler-1 o.zp.notes.spring.scheduler.DemoTask.run - call DemoTask.run

@Scheduler的使用方法

Spring的调度器一个很大的亮点在于@Scheduler注解,这可以省去很多繁琐的配置。

启动注解

使用@Scheduler注解先要使用<task:annotation-driven>启动注解开关。

例:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.1.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task-3.1.xsd"><mvc:annotation-driven/><task:annotation-driven executor="myExecutor" scheduler="myScheduler"/><task:executor id="myExecutor" pool-size="5"/><task:scheduler id="myScheduler" pool-size="10"/>
</beans>

@Scheduler定义触发条件

例:使用fixedDelay指定触发条件为每5000毫秒执行一次。注意:必须在上一次调度成功后的5000秒才能执行。

@Scheduled(fixedDelay=5000)
public void doSomething() {// something that should execute periodically
}

例:使用fixedRate指定触发条件为每5000毫秒执行一次。注意:无论上一次调度是否成功,5000秒后必然执行。

@Scheduled(fixedRate=5000)
public void doSomething() {// something that should execute periodically
}

例:使用initialDelay指定方法在初始化1000毫秒后才开始调度。

@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {// something that should execute periodically
}

例:使用cron表达式指定触发条件为每5000毫秒执行一次。cron规则和Quartz中的cron规则一致。

@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {// something that should execute on weekdays only
}

完整范例

(1) 启动注解开关,并定义调度器和执行器

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc-3.1.xsdhttp://www.springframework.org/schema/taskhttp://www.springframework.org/schema/task/spring-task-3.1.xsd"><mvc:annotation-driven/><task:annotation-driven executor="myExecutor" scheduler="myScheduler"/><task:executor id="myExecutor" pool-size="5"/><task:scheduler id="myScheduler" pool-size="10"/>
</beans>

(2) 使用@Scheduler注解来修饰一个要调度的方法

下面的例子展示了@Scheduler注解定义触发条件的不同方式。

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
import java.util.Date;/*** @description 使用@Scheduler注解调度任务范例* @author Vicotr Zhang* @date 2016年8月31日*/
@Component
public class ScheduledMgr {private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");final Logger logger = LoggerFactory.getLogger(this.getClass());/*** 构造函数中打印初始化时间*/public ScheduledMgr() {logger.info("Current time: {}", dateFormat.format(new Date()));}/*** fixedDelay属性定义调度间隔时间。调度需要等待上一次调度执行完成。*/@Scheduled(fixedDelay = 5000)public void testFixedDelay() throws Exception {Thread.sleep(6000);logger.info("Current time: {}", dateFormat.format(new Date()));}/*** fixedRate属性定义调度间隔时间。调度不等待上一次调度执行完成。*/@Scheduled(fixedRate = 5000)public void testFixedRate() throws Exception {Thread.sleep(6000);logger.info("Current time: {}", dateFormat.format(new Date()));}/*** initialDelay属性定义初始化后的启动延迟时间*/@Scheduled(initialDelay = 1000, fixedRate = 5000)public void testInitialDelay() throws Exception {Thread.sleep(6000);logger.info("Current time: {}", dateFormat.format(new Date()));}/*** cron属性支持使用cron表达式定义触发条件*/@Scheduled(cron = "0/5 * * * * ?")public void testCron() throws Exception {Thread.sleep(6000);logger.info("Current time: {}", dateFormat.format(new Date()));}
}

我刻意设置触发方式的间隔都是5s,且方法中均有Thread.sleep(6000);语句。从而确保方法在下一次调度触发时间点前无法完成执行,来看一看各种方式的表现吧。

启动spring项目后,spring会扫描@Component注解,然后初始化ScheduledMgr。

接着,spring会扫描@Scheduler注解,初始化调度器。调度器在触发条件匹配的情况下开始工作,输出日志。

截取部分打印日志来进行分析。

10:58:46.479 localhost-startStop-1 o.z.n.s.scheduler.ScheduledTasks.<init> - Current time: 2016-08-31 10:58:46
10:58:52.523 myScheduler-1 o.z.n.s.scheduler.ScheduledTasks.testFixedRate - Current time: 2016-08-31 10:58:52
10:58:52.523 myScheduler-3 o.z.n.s.scheduler.ScheduledTasks.testFixedDelay - Current time: 2016-08-31 10:58:52
10:58:53.524 myScheduler-2 o.z.n.s.scheduler.ScheduledTasks.testInitialDelay - Current time: 2016-08-31 10:58:53
10:58:55.993 myScheduler-4 o.z.n.s.scheduler.ScheduledTasks.testCron - Current time: 2016-08-31 10:58:55
10:58:58.507 myScheduler-1 o.z.n.s.scheduler.ScheduledTasks.testFixedRate - Current time: 2016-08-31 10:58:58
10:58:59.525 myScheduler-5 o.z.n.s.scheduler.ScheduledTasks.testInitialDelay - Current time: 2016-08-31 10:58:59
10:59:03.536 myScheduler-3 o.z.n.s.scheduler.ScheduledTasks.testFixedDelay - Current time: 2016-08-31 10:59:03
10:59:04.527 myScheduler-1 o.z.n.s.scheduler.ScheduledTasks.testFixedRate - Current time: 2016-08-31 10:59:04
10:59:05.527 myScheduler-4 o.z.n.s.scheduler.ScheduledTasks.testInitialDelay - Current time: 2016-08-31 10:59:05
10:59:06.032 myScheduler-2 o.z.n.s.scheduler.ScheduledTasks.testCron - Current time: 2016-08-31 10:59:06
10:59:10.534 myScheduler-9 o.z.n.s.scheduler.ScheduledTasks.testFixedRate - Current time: 2016-08-31 10:59:10
10:59:11.527 myScheduler-10 o.z.n.s.scheduler.ScheduledTasks.testInitialDelay - Current time: 2016-08-31 10:59:11
10:59:14.524 myScheduler-4 o.z.n.s.scheduler.ScheduledTasks.testFixedDelay - Current time: 2016-08-31 10:59:14
10:59:15.987 myScheduler-6 o.z.n.s.scheduler.ScheduledTasks.testCron - Current time: 2016-08-31 10:59:15

构造方法打印一次,时间点在10:58:46。

testFixedRate打印四次,每次间隔6秒。说明,fixedRate不等待上一次调度执行完成,在间隔时间达到时立即执行。

testFixedDelay打印三次,每次间隔大于6秒,且时间不固定。说明,fixedDelay等待上一次调度执行成功后,开始计算间隔时间,再执行。

testInitialDelay第一次调度时间和构造方法调度时间相隔7秒。说明,initialDelay在初始化后等待指定的延迟时间才开始调度。

testCron打印三次,时间间隔并非5秒或6秒,显然,cron等待上一次调度执行成功后,开始计算间隔时间,再执行。

此外,可以从日志中看出,打印日志的线程最多只有10个,说明2.1中的调度器线程池配置生效。

参考

Spring Framework官方文档
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/

热门内容:   

    

  • 看完知乎轮子哥的编程之路,我只想说,收下我的膝盖...

  • 这是我读过写得最好的【秒杀系统架构】分析与实战!

  • Springboot总结,核心功能,优缺点

  • 如何设计 API 接口,实现统一格式返回?

  • 阿里巴巴为什么能抗住90秒100亿?看完这篇你就明白了!

  • 日均 5 亿查询量的京东订单中心,为什么舍 MySQL 用 ES ?

  • 区块链入门教程

  • Redis 到底是怎么实现“附近的人”这个功能的呢?

  • Java 的 JSP 已经被淘汰了吗?

  • Java:如何更优雅的处理空值?

  • 为什么阿里巴巴要禁用Executors创建线程池?

最近面试BAT,整理一份面试资料《Java面试BAT通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

明天见(。・ω・。)ノ♡

Spring集成任务调度功能相关推荐

  1. Spring + Quartz任务调度实战之动态作业调度

    分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 本文地址 ...

  2. windows api中文文档_Web服务开发:Spring集成Swagger,3步自动生成API文档

    目录: 1,Spring Boot集成Swagger 2,Swagger接口文档页面 3,常见问题和解决方法 在Sping开发REST接口服务时,API文档是不可缺少的一个重要部分.Swagger框架 ...

  3. Spring集成MyBatis框架

    Spring集成MyBatis框架 Java在写数据库查询时,我接触过四种方式: 1.纯Java代码,引用对应的数据库驱动包,自己写连接与释放逻辑(可以用连接池) 这种模式实际上性能是非常不错的,但是 ...

  4. Mybatis和Spring集成 sessionFactory.openSession() 事务不生效问题

    问题描述 Mybatis和Spring集成,查阅官方文档,得知Spring总会为你处理事务. 官方文档连接:http://mybatis.org/spring/zh/transactions.html ...

  5. Spring集成Shiro框架实战

    文章目录 一:什么是Shiro框架 二:Shiro框架简介 1.Shiro基础功能点介绍 2.Shiro的工作原理 3.Shiro的内部工作结构 4.Shiro的身份认证流程 三:Spring集成Sh ...

  6. Spring集成web环境(使用封装好的工具)

    接上文spring集成web环境(手动实现) ##########代码接上文############# spring提供了一个监听器ContextLoaderListener对上述功能的封装,该监听器 ...

  7. Spring集成基础知识

    本文是我们名为" EAI的Spring集成 "的学院课程的一部分. 在本课程中,向您介绍了企业应用程序集成模式以及Spring Integration如何解决它们. 接下来,您将深 ...

  8. spring集成jndi_Spring应用程序与JNDI连接池的集成测试

    spring集成jndi 我们都知道,无论何时连接到数据库,都需要使用连接池. 所有使用JDBC 4类的现代驱动程序都支持它. 在本文中,我们将概述Spring应用程序中的连接池,以及如何在非JEE环 ...

  9. jersey spring_实施Jersey 2 Spring集成

    jersey spring Jersey是Oracle提供的出色的Java JAX-RS规范参考实现. 去年,当我们开始为大容量网站构建RESTful后端Web服务时,我们选择使用JAX-RS API ...

最新文章

  1. 洛谷P2429 制杖题 [2017年6月计划 数论10]
  2. set,env,和export的区别
  3. 遇到上亿(MySQL)大表的优化....
  4. hbase 单机连接hadoop_Hadoop、Hbase单机环境安装
  5. 数据看穿一生:前半生赚钱养娃,后半生赚钱买命
  6. ORACLE 如何产生一个随机数
  7. linux 释放进程res_linux下查询进程占用的内存方法总结
  8. 在Eclipse中配置NDK自动编译环境builders
  9. Latex常用功能模板集合
  10. 阿里云ECS服务器配置Web项目和FTP Server
  11. Windows XP SP3正式发放 官方下载
  12. 软件测试工程师自我介绍范文_软件测试工程师面试英文自我介绍范文
  13. OSPF的Router-LSA和Network-LSA
  14. sign in with Apple,使用Apple授权登录
  15. 今日头条面试——iOS开发面试题
  16. if(男深圳集体户口女非深圳户口)深圳准生证办理材料及流程
  17. mysql 横向查询
  18. 赛效:WPS中绘制的表格如何添加边框?
  19. C++基础之运算符重载
  20. python多线程请求接口_python多线程实现http请求

热门文章

  1. H国的身份证号码(搜索)
  2. Android新版NDK环境配置(免Cygwin)
  3. 基于visual Studio2013解决面试题之0804复杂链表
  4. QQ音乐API分析记录
  5. Strategy_Level2
  6. 编程基础知识科普:C#中的问号运算符
  7. echarts树图节点垂直间距_矿棉板吊顶标准工艺节点
  8. 昇思MindSpore1.6发布 AI开发者体验再升级
  9. GitLab 上市,市值高达 149 亿美元!GitHub 的头号劲敌来了
  10. 穿山甲发布聚合产品GroMore,为开发者变现赋能