實現定時任務的幾種方式:
1.使用linux的crontab
優點:
1.使用方式很簡單,只要在crontab中寫好
2.隨時可以修改,不需要重啟伺服器
缺點:
1.分散式的系統中不好使用,只能一臺臺機器去修改
2.分是最小的時間單位,秒級的不能使用
複製程式碼
2.使用spring自帶的ScheduledExecutor
優點:
cronExpression比crontab的更強大一些支援到秒,效能更好
缺點:
修改了cronExpression的重啟伺服器,否則不生效
複製程式碼
3. 使用JDK自帶的Timer
優點:
輕量級,執行速度快
缺點:
分散式系統不好使用.而且不能指定時間執行,只能按某個頻次來執行
複製程式碼
4. 使用quartz
優點:
1.可適用於分散式系統,quartz可支援叢集模式
2.修改了定時任務無須重啟伺服器(這只是我個人想到的一些優缺點,網友有其他看法可以留言說下)
複製程式碼
整合步驟:
我們現在知道了quartz有這麼優秀,該怎麼整合到專案中呢?筆者接下來將實現一個通過http介面呼叫來觸發動態定時任務的一個小功能. 筆者使用的環境: jdk:1.8.0_162; springboot:1.5.10.RELEASE 1.引入需要的jar包,在pom檔案中加入quartz的jar包和spring支援quartz的jar
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
複製程式碼
2.配置排程器的bean,這裡spring實現了三個工廠類,SchedulerFactoryBean,CronTriggerBean,JobDetailBean,使用註解的方式將這三個類交給spring管理.一般看網上的資料都是這三個類,都交給spring管理,可以參考這篇文章這篇文章。 而我這裡定時任務的觸發是要通過介面的方式來觸發,所以只用實現以下SchedulerFactoryBean的排程器即可。如果讀者不是很明白這幾個類是幹嘛的,可以看下quartz使用的文章。 我這裡簡單說下: scheduler:任務的排程器,job:具體的任務類,trigger:觸發器,任務什麼時候執行是由它決定的。就是說時間人物做什麼,scheduler就是主語的人物,trigger是時間,job是做什麼事。
@Configuration
public class SchedulerConfig {
/**
* attention:
* Details:定義quartz排程工廠
*/
@Bean(name = "scheduler")
public SchedulerFactoryBean schedulerFactory() {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
// 用於quartz叢集,QuartzScheduler 啟動時更新己存在的Job
bean.setOverwriteExistingJobs(true);
// 延時啟動,應用啟動1秒後
bean.setStartupDelay(1);
return bean;
}
}
複製程式碼
3.具體任務類job,必須實現quartz的job類,這個也可以去實現spring的QuartJobBean(spring對job類的實現)是一樣的,或者還有一種方式就是MethodInvokingJobDetailFactoryBean,這個類裡面可以設定什麼類的什麼方法來執行這個任務,會更靈活一些:
@Slf4j
public class ScheduleTaskJob implements Job {
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.info("任務執行了......");
}
}
複製程式碼
4.http的介面來觸發該排程程式:
@Slf4j
@RestController
public class Controller {
@Resource(name = "scheduler")
private Scheduler scheduler;
@PostMapping(value = "/api/executeTask")
public String executeTask(TaskVO taskVO) {
// job類
JobDetail jobDetail = JobBuilder.newJob(ScheduleTaskJob.class)
.withIdentity(taskVO.getJobName(), taskVO.getJobGroupName())
.build();
// 觸發器類
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(taskVO.getTriggerName(), taskVO.getTriggerGroupName())
.startNow()
.withSchedule(cronSchedule(taskVO.getCronExpression()))
.build();
try {
// 執行任務
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
log.error("任務執行異常", e);
}
return "success";
}
}
複製程式碼
5.http介面傳入的值物件,其實就是用來指定job和triger的name和groupName,name相同的話會失敗,必須是唯一的, 6.執行程式看看效果: 我傳入的引數: jobName:job1 jobGroupName:jobGroup1 triggerName:trigger1 triggerGroupName:triggerGroup1 cronExpression:0/1 * * * * ?
jobName:job2 jobGroupName:jobGroup1 triggerName:trigger2 triggerGroupName:triggerGroup1 cronExpression:0/1 * * * * ?
圖中紅色方框上部是隻有一個定時任務,每一秒執行一次,下部因為又加入了一個新的任務所以回答引出兩個任務的執行結果。
遇到的坑:
1.java.lang.NoSuchMethodError: org.springframework.boot.SpringApplication.run(Ljava/lang/Object;[Ljava/lang/String;)Lorg/springframework/context/ConfigurableApplicationContext; 解決方式:這個是因為springboot2不相容的問題,所以使用springboot1.5是不會出現這個錯誤的。
2.Caused by: java.lang.ClassNotFoundException: org.springframework.transaction.PlatformTransactionManager at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_162] at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_162] at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338) ~[na:1.8.0_162] at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_162] 39 common frames omitted 啟動的時候如果報這個錯的話,要引入一個spring-tx事物的包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
複製程式碼
原始碼地址:github原始碼地址,朋友們覺得寫得還行的幫忙star個,follower下,23333,感謝~
參考資料:
[1]blog.csdn.net/liuchuanhon… [2]www.w3cschool.cn/quartz_doc/… [3]www.ibm.com/developerwo… [4]www.quartz-scheduler.org/