<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在本文中,我們將看看如何使用Quartz框架來排程任務。Quartz是Java應用程式排程庫的事實標準。Quartz支援在特定時間執行作業、重複作業執行、將作業儲存在資料庫中以及Spring整合。
在 Spring 應用程式中使用 Quartz 最簡單的方法是使用@Scheduled註解。接下來,我們將考慮一個 Spring Boot 應用程式的範例。讓我們新增必要的依賴項build.gradle
implementation 'org.springframework.boot:spring-boot-starter-quartz'
並考慮一個例子
package quartzdemo.tasks; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.util.Date; @Component public class PeriodicTask { @Scheduled(cron = "0/5 * * * * ?") public void everyFiveSeconds() { System.out.println("Periodic task: " + new Date()); } }
此外,@Scheduled要使註解起作用,您需要使用@EnableScheduling註解新增設定。
package quartzdemo; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling; @SpringBootApplication @EnableScheduling public class QuartzDemoApplication { public static void main(String[] args) { SpringApplication.run(QuartzDemoApplication.class, args); } }
結果將是每五秒在控制檯中輸出一個文字。
Periodic task: Thu Jul 07 18:24:50 EDT 2022
Periodic task: Thu Jul 07 18:24:55 EDT
2022 Periodic task: Thu Jul 07 18:25:00 EDT 2022
...
@Scheduled註解支援以下引數:
預設情況下fixedRate,fixedDelay和initialDelay以毫秒為單位設定。這可以使用timeUnit引數進行更改,將值設定NANOSECONDS為DAYS。
此外,您可以在 @Scheduled 註釋中使用屬性:
application.properties
cron-string=0/5 * * * * ?
@Component public class PeriodicTask { @Scheduled(cron = "${cron-string}") public void everyFiveSeconds() { System.out.println("Periodic task: " + new Date()); } }
要使用屬性,您可以使用fixedRateString, fixedDelayString, 和initialDelayString引數來代替 fixedRate,fixedDelay和initialDelay相應的。
在前面的例子中,我們執行了定時任務,但同時我們不能動態設定作業的開始時間,也不能給它傳遞引數。要解決這些問題,可以直接使用 Quartz。
下面列出了主要的 Quartz 介面:
要直接使用 Quartz,無需使用@EnableScheduling註解定義設定org.springframework.boot:spring-boot-starter-quartz,您可以使用org.quartz-scheduler:quartz.
讓我們定義 SimpleJob 類:
package quartzdemo.jobs; import org.quartz.Job; import org.quartz.JobExecutionContext; import java.text.MessageFormat; public class SimpleJob implements Job { @Override public void execute(JobExecutionContext context) { System.out.println(MessageFormat.format("Job: {0}", getClass())); } }
要實現Job介面,您只需要實現一個execute接受JobExecutionContext型別引數的方法。JobExecutionContext包含有關作業範例、觸發器、排程程式的資訊以及有關作業執行的其他資訊。
現在讓我們定義一個作業範例:
JobDetail job = JobBuilder.newJob(SimpleJob.class).build();
並建立一個將在五秒後觸發的觸發器:
Date afterFiveSeconds = Date.from(LocalDateTime.now().plusSeconds(5) .atZone(ZoneId.systemDefault()).toInstant()); Trigger trigger = TriggerBuilder.newTrigger() .startAt(afterFiveSeconds) .build();
另外,建立一個排程程式:
SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler();
在“待機”模式下Scheduler初始化,所以我們必須呼叫start方法:
scheduler.start();
現在我們可以安排作業的執行:
scheduler.scheduleJob(job, trigger);
更進一步,在建立時JobDetails,讓我們新增額外的資料並在執行作業時使用它:
QuartzDemoApplication.java
@SpringBootApplication public class QuartzDemoApplication { public static void main(String[] args) { SpringApplication.run(QuartzDemoApplication.class, args); onStartup(); } private static void onStartup() throws SchedulerException { JobDetail job = JobBuilder.newJob(SimpleJob.class) .usingJobData("param", "value") // add a parameter .build(); Date afterFiveSeconds = Date.from(LocalDateTime.now().plusSeconds(5) .atZone(ZoneId.systemDefault()).toInstant()); Trigger trigger = TriggerBuilder.newTrigger() .startAt(afterFiveSeconds) .build(); SchedulerFactory schedulerFactory = new StdSchedulerFactory(); Scheduler scheduler = schedulerFactory.getScheduler(); scheduler.start(); scheduler.scheduleJob(job, trigger); } }
public class SimpleJob implements Job { @Override public void execute(JobExecutionContext context) { JobDataMap dataMap = context.getJobDetail().getJobDataMap(); String param = dataMap.getString("param"); System.out.println(MessageFormat.format("Job: {0}; Param: {1}", getClass(), param)); } }
需要注意的是,新增到的所有值都JobDataMap必須是可序列化的。
Quartz 將有關JobDetail、Trigger的資料和其他資訊儲存在JobStore. 預設情況下,JobStore使用記憶體。這意味著如果我們在它們被觸發之前已經安排了任務並關閉了應用程式(例如,在重新啟動或崩潰時),那麼它們將永遠不會再次執行。Quartz 還支援 JDBC-JobStore 在資料庫中儲存資訊。
在使用 JDBC-JobStore 之前,需要在 Quartz 將使用的資料庫中建立表。預設情況下,這些表的字首為QRTZ_.
Quartz 原始碼包含用於為各種資料庫(如 Oracle、Postgres、MS SQL Server、MySQL 等)建立表的SQL 指令碼,並且還有一個用於 Liquibase 的現成 XML 檔案。
spring.quartz.jdbc.initialize-schema=always此外,通過指定屬性,可以在啟動應用程式時自動建立 QRTZ 表。
為簡單起見,我們將使用第二種方法和 H2 資料庫。讓我們設定一個資料來源,使用 JDBCJobStore 並在 application.properties 中建立 QRTZ 表:
spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.quartz.job-store-type=jdbc spring.quartz.jdbc.initialize-schema=always
要考慮這些設定,必須將排程程式建立為 Spring bean:
package quartzdemo; import org.quartz.*; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import quartzdemo.jobs.SimpleJob; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; @SpringBootApplication @EnableScheduling public class QuartzDemoApplication { public static void main(String[] args) { SpringApplication.run(QuartzDemoApplication.class, args); } @Bean() public Scheduler scheduler(SchedulerFactoryBean factory) throws SchedulerException { Scheduler scheduler = factory.getScheduler(); scheduler.start(); return scheduler; } @Bean public CommandLineRunner run(Scheduler scheduler) { return (String[] args) -> { JobDetail job = JobBuilder.newJob(SimpleJob.class) .usingJobData("param", "value") // add a parameter .build(); Date afterFiveSeconds = Date.from(LocalDateTime.now().plusSeconds(5) .atZone(ZoneId.systemDefault()).toInstant()); Trigger trigger = TriggerBuilder.newTrigger() .startAt(afterFiveSeconds) .build(); scheduler.scheduleJob(job, trigger); }; } }
Quartz 在單獨的執行緒中執行每個任務,您可以為排程程式設定執行緒池。還需要注意的是,預設情況下,通過@Scheduled註解和直接通過 Quartz 啟動的任務是在不同的執行緒池中啟動的。我們可以確保這一點:
PeriodicTask.java
@Component public class PeriodicTask { @Scheduled(cron = "${cron-string}") public void everyFiveSeconds() { System.out.println(MessageFormat.format("Periodic task: {0}; Thread: {1}", new Date().toString(), Thread.currentThread().getName())); } }
SimpleJob.java
public class SimpleJob implements Job { @Override public void execute(JobExecutionContext context) { JobDataMap dataMap = context.getJobDetail().getJobDataMap(); String param = dataMap.getString("param"); System.out.println(MessageFormat.format("Job: {0}; Param: {1}; Thread: {2}", getClass(), param, Thread.currentThread().getName())); } }
輸出將是:
Periodic task: Thu Jul 07 19:22:45 EDT 2022; Thread: scheduling-1 Job: class quartzdemo.jobs.SimpleJob; Param: value; Thread: quartzScheduler_Worker-1 Periodic task: Thu Jul 07 19:22:50 EDT 2022; Thread: scheduling-1 Periodic task: Thu Jul 07 19:22:55 EDT 2022; Thread: scheduling-1 Periodic task: Thu Jul 07 19:23:00 EDT 2022; Thread: scheduling-1
任務的執行緒池@Scheduled只包含一個執行緒。
讓我們更改 @Scheduled 任務的排程程式設定:
package quartzdemo; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.SchedulingConfigurer; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import org.springframework.scheduling.config.ScheduledTaskRegistrar; @Configuration public class SchedulingConfiguration implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); threadPoolTaskScheduler.setPoolSize(10); threadPoolTaskScheduler.setThreadNamePrefix("my-scheduled-task-pool-"); threadPoolTaskScheduler.initialize(); taskRegistrar.setTaskScheduler(threadPoolTaskScheduler); } }
輸出現在將是這樣的:
Periodic task: Thu Jul 07 19:44:10 EDT 2022; Thread: my-scheduled-task-pool-1 Job: class quartzdemo.jobs.SimpleJob; Param: value; Thread: quartzScheduler_Worker-1 Periodic task: Thu Jul 07 19:44:15 EDT 2022; Thread: my-scheduled-task-pool-1 Periodic task: Thu Jul 07 19:44:20 EDT 2022; Thread: my-scheduled-task-pool-2
如您所見,這些設定僅影響使用註釋設定的任務。
現在讓我們更改直接使用 Quartz 的排程程式的設定。這可以通過兩種方式完成:通過屬性檔案或通過建立 bean SchedulerFactoryBeanCustomizer。
讓我們使用第一種方法。如果我們沒有通過 Spring 初始化 Quartz,我們將不得不在 quartz.properties 檔案中註冊屬性。在我們的例子中,我們需要在 application.properties 中註冊屬性,並spring.quartz.properties.為其新增字首。
application.properties
spring.quartz.properties.org.quartz.threadPool.threadNamePrefix=my-scheduler_Worker spring.quartz.properties.org.quartz.threadPool.threadCount=25
讓我們啟動應用程式。現在輸出將是這樣的:
Periodic task: Sat Jul 23 10:45:55 MSK 2022; Thread: my-scheduled-task-pool-1 Job: class quartzdemo.jobs.SimpleJob; Param: value; Thread: my-scheduler_Worker-1
現在呼叫啟動任務的執行緒my-scheduler_Worker-1。
如果您需要建立多個具有不同引數的排程程式,則必須定義多個SchedulerFactoryBeans. 讓我們看一個例子。
package quartzdemo; import quartzdemo.jobs.SimpleJob; import org.quartz.*; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import javax.sql.DataSource; import java.time.LocalDateTime; import java.time.ZoneId; import java.util.Date; import java.util.Properties; @SpringBootApplication @EnableScheduling public class QuartzDemoApplication { public static void main(String[] args) { SpringApplication.run(QuartzDemoApplication.class, args); } @Bean("customSchedulerFactoryBean1") public SchedulerFactoryBean customSchedulerFactoryBean1(DataSource dataSource) { SchedulerFactoryBean factory = new SchedulerFactoryBean(); Properties properties = new Properties(); properties.setProperty("org.quartz.threadPool.threadNamePrefix", "my-custom-scheduler1_Worker"); factory.setQuartzProperties(properties); factory.setDataSource(dataSource); return factory; } @Bean("customSchedulerFactoryBean2") public SchedulerFactoryBean customSchedulerFactoryBean2(DataSource dataSource) { SchedulerFactoryBean factory = new SchedulerFactoryBean(); Properties properties = new Properties(); properties.setProperty("org.quartz.threadPool.threadNamePrefix", "my-custom-scheduler2_Worker"); factory.setQuartzProperties(properties); factory.setDataSource(dataSource); return factory; } @Bean("customScheduler1") public Scheduler customScheduler1(@Qualifier("customSchedulerFactoryBean1") SchedulerFactoryBean factory) throws SchedulerException { Scheduler scheduler = factory.getScheduler(); scheduler.start(); return scheduler; } @Bean("customScheduler2") public Scheduler customScheduler2(@Qualifier("customSchedulerFactoryBean2") SchedulerFactoryBean factory) throws SchedulerException { Scheduler scheduler = factory.getScheduler(); scheduler.start(); return scheduler; } @Bean public CommandLineRunner run(@Qualifier("customScheduler1") Scheduler customScheduler1, @Qualifier("customScheduler2") Scheduler customScheduler2) { return (String[] args) -> { Date afterFiveSeconds = Date.from(LocalDateTime.now().plusSeconds(5).atZone(ZoneId.systemDefault()).toInstant()); JobDetail jobDetail1 = JobBuilder.newJob(SimpleJob.class).usingJobData("param", "value1").build(); Trigger trigger1 = TriggerBuilder.newTrigger().startAt(afterFiveSeconds).build(); customScheduler1.scheduleJob(jobDetail1, trigger1); JobDetail jobDetail2 = JobBuilder.newJob(SimpleJob.class).usingJobData("param", "value2").build(); Trigger trigger2 = TriggerBuilder.newTrigger().startAt(afterFiveSeconds).build(); customScheduler2.scheduleJob(jobDetail2, trigger2); }; } }
輸出:
Job: class quartzdemo.jobs.SimpleJob; Param: value2; Thread: my-custom-scheduler2_Worker-1 Job: class quartzdemo.jobs.SimpleJob; Param: value1; Thread: my-custom-scheduler1_Worker-1
Quartz 是一個用於自動執行計劃任務的強大框架。它既可以在簡單直觀的 Spring 註解的幫助下使用,也可以通過精細的客製化和調整來使用,從而為複雜的問題提供解決方案。
到此這篇關於在SpringBoot中使用Quartz排程作業的範例詳解的文章就介紹到這了,更多相關SpringBoot排程作業內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45