Spring调度和后台任务
Spring应用上下文中添加一行配置:
xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd"
元素是Spring自动支持调度和异步方法。这些方法分别使用@Scheduled和@Async来进行标注。
1、声明调度方法
//每隔24小时(86 400 000毫秒)触发一个方法:
@Scheduled(fixedRate=86400000)
public void archiveOldSpittles(){
//...
}
属性fixedRate表明这个方法需要每隔指定的毫秒数进行周期性地调用。在上面的示例中,每次方法开始调用之间要经历86,400,000毫秒。如果你想指定调用之间的间隔(也就是一次调用完成与下一次调用开始之间的间隔),那需要使用fixedDelay属性:
@Scheduled(fixedDelay=86400000)
public void archiveOldSpittles(){
//...
}
在指定间隔后运行任务是很便利的。但是,你可能先概要更精确地控制方法调用。使用fixedRate和fixedDelay只能指定方法调用的频率,但是并不能确定方法在何时调用。为了更确切地指定方法在什么时间调用,可以使用cron属性:
@Scheduled(cron="0 0 0 * * SAT")
public void archiveOldSpittles(){
//...
}
赋予cron属性的值是一个Cron表达式。如果你不熟悉Cron表达式,那么我们详细介绍一下cron属性。Cron表达式由6个(或者7个)空格分隔的时间元素构成。从左至右,元素定义如下:
秒(0-59);
分钟(0-59);
小时(0-23);
月份中的日期(1-31);
月份(1-12 或 JAN-DEC);
星期中的日期(1-7 或 SUN-SAT);
年份(1970-2099);
每个元素都可以显式地指定值、范围、列表或者通配符(*)。月份中的日期和星期中的日期这两个元素是互斥的,因此应该通过设置一个问号(?)来表明你不想设置的那个字段。如下表:
Cron表达式 含义
0 0 10,14,16 * * ? 每天的10点、14点、16点
0 0,15,30,45 * 1-30 * ? 每个月前30天每隔15分钟
30 0 0 1 1 ? 2012 2012年1月1日00:00:30时
0 0 8-17 ? * MON-FRI 每个工作日的工作时间
2、声明异步方法
当谈及面向人类用户的应用程序性能时,会有两种类型的应用性能:实际上的和感知上的。应用程序的实际性能(actual performance),指的是独立测量完成一项操作需要多长时间。实际性能当然很重要,即便实际性能并不理想,但可以通过感知性能改善用户的体验。
感知性能(perceived performance)恰好如其名所示。只要用户能够独立即看到变化,谁会关心背后耗用多少时间呢?例如,假设添加Spittle实际上是耗时的操作。如果同步执行,感知性能就是一个方法的实际性能。在Spittle真正保存之前,用户必须等待。
但是如果SpitterService的saveSpittle()方法可以实现异步执行。那么应用可以在执行后台持久化逻辑时为用户展现一个新的页面。这就是@Async注解所做的事情。
@Async是一个很简单的注解,它没有要设置的属性。你所需要做的就是将其用与Bean的方法上,这个方法就会称为异步的了。
例如
@Async
public void addSpittle(Spittle spittle){
//...
}
就是这样。当saveSpittle()方法被调用的时候,控制权会立即交给调用者。同时,saveSpittle()方法将会在后台继续运行。
你可能想知道如果异步方法需要返回值给调用者会怎么样?如果异步方法立即返回的话,那它如何传递结果给调用者呢?
因为Spring的异步方法是简历在Java的并发API(Javaconcurrency API)之上的,它可以返回实现java.util.concurrent.Future的对象。这个接口代表了一个值的容器,而值能在方法返回后的某个时间点得到,但并不一定是方法返回的时间点。Spring还自带了一个Future的便利实现,名为AsyncResult,借助与它可以更容易地处理未来的值。
例如,假设你有一个异步方法要执行复杂和长时间运行的计算。你希望在后台执行方法,但是还想在方法执行完成时马上看到结果。在这种情况下,你可将方法这样编写:
@Async
public Future performSomeReallyHairyMath(long input){
//...
return new AsyncResult(result);
}
这个方法可以耗用很长的时间来产生结果,与此同时调用者可以执行其他要做的业务。在结果的计算过程中,调用者会持有一个Future对象(实际上是AsyncResult)。
一旦得到结果,调用者可以通过调用Future对象的get()方法来得到它。在此之前,调用者可以使用isDone()和isCancelled()来判断结果的状态。
本文摘自Spring实战14.4调度和后台任务
上一篇: spring 事件机制 异步操作
下一篇: springboot异步调用的方法
推荐阅读
-
Spring boot 和Vue开发中CORS跨域问题解决
-
spring boot 使用Aop通知打印控制器请求报文和返回报文问题
-
Spring MVC源码(三) ----- @RequestBody和@ResponseBody原理解析
-
基于Spring Cloud Netflix的TCC柔性事务和EDA事件驱动示例
-
浅析Linux中使用nohup及screen运行后台任务的示例和区别
-
Spring Cloud开发人员如何解决服务冲突和实例乱窜?(IP实现方案)
-
品Spring:对@Autowired和@Value注解的处理方法
-
spring集成mybatis原理(spring和mybatis整合步骤)
-
Spring学习之动态代理(JDK动态代理和CGLIB动态代理)
-
详解Linux内核进程调度函数schedule()的触发和执行时机