spring task是spring 3.0以后推出的定時器類红且,可以把它當(dāng)做一個輕量級的quartz泉懦。由于配置簡單汉匙,功能齊全拱烁,在實際項目中經(jīng)常會用到生蚁。spring task支持xml配置、注解配置戏自、java配置三種方式邦投。
方式一:xml配置
1. 定義任務(wù)類
package com.sawyer.job;
import java.util.Date;
public class TaskTest {
public void run() {
System.out.println(new Date() + " and current thread is " + Thread.currentThread().getName());
}
}
2. 在xml中聲明bean
<?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-4.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<!-- task -->
<bean id="taskTest" class="com.sawyer.job.TaskTest"/>
<task:scheduled-tasks>
<task:scheduled ref="taskTest" method="run" cron="0/5 * * * * ?" />
</task:scheduled-tasks>
</beans>
3. 運行結(jié)果
Tue Jul 18 15:22:40 CST 2017 and current thread is scheduler-1
Tue Jul 18 15:22:45 CST 2017 and current thread is scheduler-1
Tue Jul 18 15:22:50 CST 2017 and current thread is scheduler-2
Tue Jul 18 15:22:55 CST 2017 and current thread is scheduler-1
Tue Jul 18 15:23:00 CST 2017 and current thread is scheduler-3
Tue Jul 18 15:23:05 CST 2017 and current thread is scheduler-2
Tue Jul 18 15:23:10 CST 2017 and current thread is scheduler-4
Tue Jul 18 15:23:15 CST 2017 and current thread is scheduler-1
Tue Jul 18 15:23:20 CST 2017 and current thread is scheduler-5
Tue Jul 18 15:23:25 CST 2017 and current thread is scheduler-3
Tue Jul 18 15:23:30 CST 2017 and current thread is scheduler-3
4. 參數(shù)說明
- scheduled-tasks中可以定義多個task,這里指定了一個task擅笔,上圖中 ref 指定任務(wù)類志衣,method指定執(zhí)行方法,cron指定頻率猛们,這里表示每隔5秒執(zhí)行一下念脯。
- task中用于指定時間頻率的方式,有以下幾種:
cron:cron表達(dá)式十分強大弯淘,可以指定秒绿店、分、時庐橙、日期假勿、月份、星期幾态鳖,格式為 * * * * * 转培?
fixed-rate:單位毫秒,每隔指定時間就執(zhí)行一次
fixed-delay:單位毫秒浆竭,上次任務(wù)執(zhí)行完后堡距,間隔指定時間后執(zhí)行下次任務(wù)
initial-delay:單位毫秒,首次執(zhí)行任務(wù)的時候兆蕉,延遲指定時間執(zhí)行。- spring task 默認(rèn)使用的是同步模式缤沦,即上次任務(wù)執(zhí)行完后虎韵,才會執(zhí)行下次任務(wù)。上述時間頻率只有在非同步模式下才會完全符合缸废,在同步模式下包蓝,實際計算方式為:
fixed-rate :任務(wù)的實際執(zhí)行時間+fixedRate時間之后,執(zhí)行下次任務(wù)
fixed-delay:任務(wù)的實際執(zhí)行時間如果小于fixedDelay企量,則時間間隔為fixedDelay测萎;如果任務(wù)的實際執(zhí)行時間大于fixedDelay,則上次任務(wù)執(zhí)行完后届巩,立即執(zhí)行下一次任務(wù)硅瞧。
5. 由于上述原因,實際開發(fā)的時候都會為spring task 設(shè)置線程池恕汇。設(shè)置線程池的方式腕唧,我會在注解配置中說明或辖,而注解配置也是目前最為推薦的一種。
方式二:注解配置
1. 定義任務(wù)類
package com.sawyer.job;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class TaskTest {
@Scheduled(cron = "0/2 * * * * ?")
@Async("executor")
public void run() {
System.out.println(new Date() + " and current thread is " + Thread.currentThread().getName());
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
2. 聲明 bean
<?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:context="http://www.springframework.org/schema/context"
xmlns:task="http://www.springframework.org/schema/task"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
<!-- task -->
<context:component-scan base-package="com.sawyer.job"/>
<task:executor id="executor" pool-size="10-15" queue-capacity="10" keep-alive="30000" rejection-policy="DISCARD"/>
<task:scheduler id="scheduler" pool-size="10"/>
<task:annotation-driven executor="executor" scheduler="scheduler"/>
</beans>
3. 參數(shù)說明
- 使用@Async開啟異步模式枣接,@Async的值為執(zhí)行器executor颂暇,名字需要與xml中配置的一致。
- executor用于配置線程池
- pool-size:線程池數(shù)量但惶,可以設(shè)置范圍耳鸯,也可以設(shè)置指定值,最小值為1膀曾,最大值為Integer.MAX_VALUE县爬。
- queue-capacity:任務(wù)隊列,當(dāng)線程數(shù)達(dá)到最小值時妓肢,新任務(wù)將會被放到隊列中捌省。當(dāng)隊列被占滿時,executor就會在線程池中創(chuàng)建新的線程碉钠,執(zhí)行新的任務(wù)纲缓。
- keep-alive:pool-size的最小值是指核心線程的數(shù)量,超過這個數(shù)的其他線程喊废,當(dāng)執(zhí)行完任務(wù)后祝高,可以存活keep-alive指定的時間,單位毫秒污筷。
- rejection-policy:當(dāng)線程數(shù)達(dá)到最大值時工闺,系統(tǒng)的處理策略,可以設(shè)置4種方式:
ABOAT:默認(rèn)值瓣蛀,拋出異常陆蟆,不再執(zhí)行新的任務(wù),直到有空閑線程可以使用
DISCARD:不拋出異常惋增,不再執(zhí)行新的任務(wù)叠殷,知道有空閑線程可以使用
CALLER_RUNS:在當(dāng)前線程中執(zhí)行新的任務(wù)
DISCARD_OLDEST:丟棄最舊的一個任務(wù),空出線程執(zhí)行新的任務(wù)
動態(tài)修改時間
在實際的生產(chǎn)環(huán)境中诈皿,有可能需要動態(tài)的修改任務(wù)的時間頻率林束,在spring task中只需要實現(xiàn)SchedulingConfigurer接口即可
package com.sawyer.job;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class TestTask implements SchedulingConfigurer {
private String cron = "0/3 * * * * ?";
private int i = 0;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(() -> {
i++;
System.out.println("Now is " + new Date()+" and the thread is "+Thread.currentThread().getName());
if (i == 12) {
cron = "0/5 * * * * ?";
}
if (i == 24) {
cron = "0/2 * * * * ?";
}
}, triggerContext -> {
CronTrigger cronTrigger = new CronTrigger(cron);
return cronTrigger.nextExecutionTime(triggerContext);
});
}
}
上述例子只是簡單的范例,可以根據(jù)需要進(jìn)行改進(jìn)
總結(jié)
spring task配置簡單稽亏,能夠滿足實際開發(fā)中的大部分需要壶冒。但是當(dāng)需要保護(hù)事故現(xiàn)場,或者需要動態(tài)的暫停截歉、刪除任務(wù)的話胖腾,spring task就不是很適用了。即使在spring task的基礎(chǔ)上去實現(xiàn)這些功能,最終得到的效果可能也并不是很理想胸嘁。這種時候就需要用到調(diào)度框架Quartz了瓶摆。