第11章 任务调度

任务调度由三部分组成:

  • 任务:需要在特定时间运行或定期运行的业务逻辑块;
  • 触发器:指定任务应该执行的条件;
  • 调度程序:根据来自触发器的信息执行任务;

11.2 Spring中的任务调度

在Spring应用程序中可以使用多种方法触发任务的执行。

一种方法是通过已存在于应用程序部署环境中的调度系统从外部触发作业。作业触发可以通过向Spring应用程序发送RESTful-WS请求并让Spring的MVC控制器触发任务来完成。

另一种方法是在Spring中使用任务调度支持。Spring在任务调度方面提供了三个选项:

  • 支持JDK定时器
  • 与Quartz集成
  • Spring自己的Spring TaskScheduler抽象

11.2.1 Spring TaskScheduler抽象介绍

Spring的TaskScheduler抽象主要有三个参与者:

  • 任务:可以指定为任何Spring bean的方法
  • Trigger接口:org.springframework.scheduling.Trigger
  • TaskScheduler接口:org.springframework.scheduling.TaskScheduler

11.2.2 研究示例任务

使用XML配置和Java配置结合的方式配置简单任务调度:

// ----XML配置--------//
<?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:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> <task:scheduler id="timeScheduler" pool-size="10"/> <task:scheduled-tasks>
<task:scheduled ref="testSchedulerConfig" method="sayTime" fixed-delay="3000"/>
</task:scheduled-tasks> </beans> // ----Java配置与测试--------//
@Slf4j
@Configuration
@Component("testSchedulerConfig")
@ImportResource("classpath:chapter11/ac_task_test.xml")
public class TestSchedulerConfig { public void sayTime() {
log.error("======" + new Date().toLocaleString());
} public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestSchedulerConfig.class); }
}

11.2.3 使用注解进行任务调度

Spring提供了@Scheduled注解来使用Spring的TaskScheduler抽象。要使用注解支持,可以在XML配置中使用<task:annotation-driver>标记或在配置类上使用@EnableScheduling注解。

@Slf4j
@Configuration
@EnableScheduling
public class TestAnnoSchedulerConfig { @Scheduled(fixedRate = 1000)
public void sayTime() {
log.error("======" + new Date().toLocaleString());
} public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TestAnnoSchedulerConfig.class); }
}

任务调度原理:

org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor

这个类既是后置处理器,又是事件监听器,监听ContextRefreshedEvent事件;

refresh()--finishBeanFactoryInitialization()中调用后置处理器方法进行配置;在refresh()--finishRefresh();中通过事件监听的方式开始执行任务调度;

11.2.4 Spring中异步任务的执行

Spring使用@Async注解来异步执行任务。

// ----------定义异步任务-------------//
@Slf4j
@Service("asyncService")
public class AsyncServiceImpl implements AsyncService {
@Async
@Override
public void asyncTask() {
log.error("AsyncServiceImpl...asyncTask...111"); try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
} log.error("AsyncServiceImpl...asyncTask...222");
} @Async
@Override
public Future<String> asyncWithReturn(String name) {
log.error("AsyncServiceImpl...asyncWithReturn...111==" + name); try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.error("AsyncServiceImpl...asyncWithReturn...222==" + name);
return new AsyncResult<>("Hello: " + name);
}
} // ----------定义Java配置-------------//
@Configuration
@EnableAsync
@Import({AsyncServiceImpl.class})
public class AsyncConfig { } // ----------测试程序-------------//
@Slf4j
public class AsyncTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AsyncConfig.class);
AsyncService asyncService = ctx.getBean("asyncService", AsyncService.class); for (int i = 0; i < 5; i++) {
asyncService.asyncTask();
} Future<String> result1 = asyncService.asyncWithReturn("John Mayer");
Future<String> result2 = asyncService.asyncWithReturn("Eric Clapton");
Future<String> result3 = asyncService.asyncWithReturn("BB King"); log.error("result1 == " + result1.get());
log.error("result2 == " + result2.get());
log.error("result3 == " + result3.get());
}
}

原理:基于后置处理器org.springframework.scheduling.annotation.AsyncAnnotationBeanPostProcessor

11.3 Spring中任务的执行

Spring通过TaskExecutor接口执行任务的抽象。TaskExecutor执行由Java Runnable实现表示的任务。Spring提供了很多适合不同需求的TaskExecutor实现。

  • SimpleAsyncTaskExecutor:在每次调用时创建新线程,不重用现有的线程。
  • SyncTaskExecutor:不会异步执行,调用发生在调用线程中。
  • SimpleThreadPoolTaskExecutor:Quartz的SimpleThreadPool的子类,但需要Quartz和非Quartz组件之间共享线程池时使用。
  • ThreadPoolTaskExecutor:TaskExecutor的一种实现,提供了通过bean属性配置java.util.concurrent.ThreadPoolExecutor并将其作为Spring TaskExecutor公开的功能。
// --------定义执行任务----------- //
@Slf4j
@Component
public class TaskToExecute {
@Autowired
private TaskExecutor taskExecutor; public void executeTask() {
for (int i = 0; i < 10; i++) {
taskExecutor.execute(() -> log.info("Hello from thread: " + Thread.currentThread().getName()));
}
}
} // --------定义Java配置类----------- //
@Configuration
@EnableAsync
@Import({TaskToExecute.class})
public class TaskConfig {
@Bean
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}
} // --------测试程序----------- //
public class TaskExecutorDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(TaskConfig.class); TaskToExecute taskToExecute = ctx.getBean(TaskToExecute.class);
taskToExecute.executeTask(); ctx.close();
}
}

通过Async注解异步执行时,默认使用的是SimpleAsyncTaskExecutor,如果没有定义类型为TaskExecutor的bean或名称为taskExecutor的类型为Executor的bean。

20191105 《Spring5高级编程》笔记-第11章的更多相关文章

  1. C#高级编程笔记之第二章:核心C#

    变量的初始化和作用域 C#的预定义数据类型 流控制 枚举 名称空间 预处理命令 C#编程的推荐规则和约定 变量的初始化和作用域 初始化 C#有两个方法可以一确保变量在使用前进行了初始化: 变量是字段, ...

  2. C#高级编程9 第11章 Linq

    Linq 1.Linq概述 列表和实体 准备数据: public class Championship { public int Year { get; set; } public string Fi ...

  3. C#高级编程笔记之第一章:.NET体系结构

    1.1 C#与.NET的关系 C#不能孤立地使用,必须与.NET Framework一起使用一起考虑. (1)C#的体系结构和方法论反映了.NET基础方法论. (2)多数情况下,C#的特定语言功能取决 ...

  4. 20191105 《Spring5高级编程》笔记-【目录】

    背景 开始时间:2019/09/18 21:30 Spring5高级编程 版次:2019-01-01(第5版) Spring5最新版本:5.1.9 CURRENT GA 官方文档 Spring Fra ...

  5. 读《C#高级编程》第1章问题

    读<C#高级编程>第1章 .Net机构体系笔记 网红的话:爸爸说我将来会是一个牛逼的程序员,因为我有一个梦,虽然脑壳笨但是做事情很能坚持. 本章主要是了解.Net的结构,都是一些概念,并没 ...

  6. Android高级编程笔记(四)深入探讨Activity(转)

    在应用程序中至少包含一个用来处理应用程序的主UI功能的主界面屏幕.这个主界面一般由多个Fragment组成,并由一组次要Activity支持.要在屏幕之间切换,就必须要启动一个新的Activity.一 ...

  7. C#高级编程9 第18章 部署

    C#高级编程9 第18章 部署 使用 XCopy 进行部署 本主题演示如何通过将应用程序文件从一台计算机复制到另一台计算机来部署应用程序. 1.将项目中生成的程序集复制到目标计算机,生成的程序集位于项 ...

  8. C#高级编程9 第17章 使用VS2013-C#特性

    C#高级编程9 第17章 使用VS2013 编辑定位到 如果默认勾选了这项,请去掉勾选,因为勾选之后解决方案的目录会根据当前文件选中. 可以设置项目并行生成数 版本控制软件设置 所有文本编辑器行号显示 ...

  9. C#高级编程9 第16章 错误和异常

    C#高级编程9 第16章 错误和异常 了解这章可以学会如何处理系统异常以及错误信息. System.Exception类是.NET运行库抛出的异常,可以继承它定义自己的异常类. try块代码包含的代码 ...

随机推荐

  1. deletefile 与KILL

    1.Kill 语句 从磁盘中删除文件.语法Kill pathname必要的 pathname 参数是用来指定一个文件名的字符串表达式.pathname 可以包含目录或文件夹.以及驱动器.说明在 Mic ...

  2. 为什么我选择用 flutter

    1. flutter 生成的是机器代码,他既不是 hybrid 也不是transpiler,  因此有很高的执行效率. 2. declarative ui,这不是什么新的概念,在 react vue ...

  3. js赋值后 改变现有数据会修改原来的数据

    看代码: let obj1 = { name: '张三', age: , sex: '男' } let obj2 = obj1 console.log('obj2:', obj2) obj2.age ...

  4. Keras MAE和MSE source code

    def mean_squared_error(y_true, y_pred): if not K.is_tensor(y_pred): y_pred = K.constant(y_pred) y_tr ...

  5. react native 之 redux 使用套路

    redux是什么?他是一个state容器 redux的运作方式是怎样的? 接入方式: 1. npm install 下列内容: npm install --save redux npm install ...

  6. Activiti创建表(三)

    创建Mysql 创建 mysql 数据库 activiti(名字任意):CREATE DATABASE activiti DEFAULT CHARACTER SET utf8; pom.xml < ...

  7. HDU-6703 array

    Description You are given an array a1,a2,...,an(∀i∈[1,n],1≤ai≤n). Initially, each element of the arr ...

  8. Nginx动静分离-tomcat

    一.动静分离 1.通过中间件将动态请求和静态请求分离. 2.为什么? 分离资源,减少不必要的请求消耗,减少请求延时. 3.场景 还可以利用php,fastcgi,python 等方式 处理动态请求 # ...

  9. 一本通&&洛谷——P1120 小木棍 [数据加强版]——题解

    题目传送 一道特别毒瘤能提醒人不要忘记剪枝的题. 首先不要忘了管理员的话.忘把长度大于50的木棍过滤掉真的坑了不少人(包括我). 显然是一道DFS题 .考虑剪枝. 找找搜索要面临的维度.状态:原始木棍 ...

  10. Android环境配置之正式版AndroidStudio1.0

    昨天看见 Android Studio 1.0 正式版本发布了:心里挺高兴的. 算是忠实用户了吧,从去年开发者大会一开始出现 AS 后就开始使用了:也是从那时开始就基本没有用过 Eclipse 了:一 ...