springboot整合quartz項目使用案例
前言:quartz是一個定時調度的框架,就目前市場上來說,其實有比quartz更優秀的一些定時調度框架,不但性能比quartz好,學習成本更低,而且還提供可視化操作定時任務。例如xxl-Job,elastic-Job這兩個算是目前工作中使用比較多的定時調度框架瞭,適配於分佈式的項目,性能也是很優秀。這是很多人就很疑惑,既然這樣我們為什麼還要瞭解學習quartz呢?我個人覺得學習quartz有兩方面,首先xxl-Job,elastic-Job這些框架都是基於quartz的基礎上二次開發的,學習quartz更有利於我們加強理解定時調度。第二方面就是工作需求,有一些傳統互聯網公司還是有很多項目是使用quartz來完成定時任務的開發的,不懂quartz的話,老板叫你寫個定時任務都搞不定。
1. quartz的基礎概念
有上圖可以看到,一個job可以給多個jobDetail封裝,一個jobDetail可以給trigger來配置規則,但是一個trigger隻能裝配一個jobDetail。
scheduler:可以理解為定時任務的工作容器或者說是工作場所,所有定時任務都是放在裡面工作,可以開啟和停止。
trigger:可以理解為是定時任務任務的工作規則配置,例如說,沒個幾分鐘調用一次,或者說指定每天那個時間點執行。
jobDetail:定時任務的信息,例如配置定時任務的名字,群組之類的。
job:定時任務的真正的業務處理邏輯的地方。
2. quartz的簡單使用
這是quartz的api使用,在官網直接提供使用例子,但是在工作中用不到這種方式的
地址:https://www.quartz-scheduler.org/documentation/quartz-2.3.0/quick-start.html
public class QuartzTest { public static void main(String[] args) throws Exception{ try { Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); scheduler.start(); JobDetail job = newJob(HelloJob.class) .withIdentity("job1", "group1") .build(); Trigger trigger = newTrigger() .withIdentity("trigger1", "group1") .startNow() .withSchedule(simpleSchedule() .withIntervalInSeconds(2) .repeatForever()) .build(); scheduler.scheduleJob(job, trigger); TimeUnit.SECONDS.sleep(20); scheduler.shutdown(); } catch (SchedulerException se) { se.printStackTrace(); } } }
3. quartz與springboot的整合使用
在官網中介紹瞭,隻要你引用瞭quartz的依賴後,springboot會自適配調度器。當然我們也可以新建bean,修改SchedulerFactoryBean的一些默認屬性值。
使用javaBean方式按實際業務需求初始化SchedulerFactoryBean(可以不要,就用默認SchedulerFactoryBean
@Configuration public class QuartzConfiguration { // Quartz配置文件路徑 private static final String QUARTZ_CONFIG = "config/quartz.properties"; @Value("${task.enabled:true}") private boolean enabled; @Autowired private DataSource dataSource; @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); schedulerFactoryBean.setDataSource(dataSource); // 設置加載的配置文件 schedulerFactoryBean.setConfigLocation(new ClassPathResource(QUARTZ_CONFIG)); // 用於quartz集群,QuartzScheduler 啟動時更新己存在的Job schedulerFactoryBean.setOverwriteExistingJobs(true); schedulerFactoryBean.setStartupDelay(5);// 系統啟動後,延遲5s後啟動定時任務,默認為0 // 啟動時更新己存在的Job,這樣就不用每次修改targetObject後刪除qrtz_job_details表對應記錄瞭 schedulerFactoryBean.setOverwriteExistingJobs(true); // SchedulerFactoryBean在初始化後是否馬上啟動Scheduler,默認為true。如果設置為false,需要手工啟動Scheduler schedulerFactoryBean.setAutoStartup(enabled); return schedulerFactoryBean; } }
要使用quartz實現定時任務,首先要新建一個Job,在springboot中,新建的Job類要繼承QuartzJobBean
public class HelloJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext context) { StringJoiner joiner = new StringJoiner(" | ") .add("---HelloJob---") .add(context.getTrigger().getKey().getName()) .add(DateUtil.formatDate(new Date())); System.out.println(joiner); } }
創建jobDetail和Trigger來啟動定時任務,有兩種方式可以實現,本質上就是創建jobDetail和Trigger
方式一:為對應的Job創建JobDetail和Trigger,這種方式有兩個註意的地方,jobDetail一定要設置為可持久化.storeDurably(),Trigger創建要用.forJob(“helloJob”),要與JobDetail定義的相同。
@Component public class HelloJobDetailConfig { @Bean public JobDetail helloJobDetail(){ JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) .withIdentity("helloJob") .storeDurably() .usingJobData("data", "保密信息") .build(); return jobDetail; } @Bean public Trigger helloJobTrigger(){ Trigger trigger = TriggerBuilder.newTrigger() .forJob("helloJob") .withSchedule(simpleSchedule() .withIntervalInSeconds(3) .repeatForever()) .build(); return trigger; } }
方式二:在註入Bean之前初始化創建JobDetail和Trigger,然後使用Scheduler來調用,跟原生API調用差不多。
@Component public class HelloJobDetailConfig2 { @Autowired private Scheduler scheduler; @PostConstruct protected void InitHelloJob() throws Exception { JobDetail jobDetail = JobBuilder.newJob(HelloJob.class) .withIdentity("helloJob") // .storeDurably() .usingJobData("data", "保密信息") .build(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity("helloTrigger") .withSchedule(simpleSchedule() .withIntervalInSeconds(3) .repeatForever()) .build(); scheduler.scheduleJob(jobDetail,trigger); } }
4. quartz的持久化
quartz持久化有兩種存儲,一般情況下quartz相關的表和業務表是放在同一個數據庫裡的。但是如果考慮性能問題的話,就要配多數據源,業務表單獨一個庫,quartz相關的表放在一個庫。
https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/spring-boot-features.html#boot-features-quartz
spring官網說明,默認情況下,使用內存中的JobStore。但是,如果應用程序中有DataSourcebean,並且spring.quartz是可用的,則可以配置基於JDBC的存儲。將相應地配置作業存儲類型屬性。第二個配置,每次啟動先刪除表數據再重新創建(在實際生產中,個人更傾向於拿dml來手動創建表,這個值設置為never)。在quartz的jar包裡這個路徑下有不同數據庫的dml:org.quartz.impl.jdbcjobstore
spring.quartz.job-store-type=jdbc
spring.quartz.jdbc.initialize-schema=never
另外一種方式:
要讓Quartz使用DataSource而不是應用程序的主DataSource,請聲明DataSourcebean,並用@QuartzDataSource註釋其@bean方法。這樣做可以確保SchedulerFactoryBean和模式初始化都使用Quartz特定的DataSource
@Configuration public class QuartzDataSourceConfig { @Bean @QuartzDataSource public DataSource quartzDataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setUsername("root"); dataSource.setPassword("123456"); dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=utf-8&useSSL=false"); return dataSource; } }
還有一點需要註意:當jobbean已經註入spring容器後,下次不用需要再註入,把@Component註釋掉。
5. quartz的misfire策略
**misfire:**到瞭任務觸發時間點,但是任務沒有被觸發
原因:- 使用@DisallowConcurrentExecution註解,而且任務的執行時間>任務間隔
-線程池滿瞭,沒有資源執行任務
-機器宕機或者認為停止,果斷時間恢復運行。
@DisallowConcurrentExecution:這個是比較常用的註解,證上一個任務執行完後,再去執行下一個任務,不會允許任務並行執行。
@PersistJobDataAfterExecution:任務執行完後,會持久化保留數據到下次 執行
針對不同的ScheduleBuilder,可以設置不同的失火策略,SimpleScheduleBuilder和非SimpleScheduleBuilder,
SimpleScheduleBuilder有六種,而非SimpleScheduleBuilder有三種,在實際工作中我們使用的比較的是CronScheduleBuilder.
.withMisfireHandlingInstructionIgnoreMisfires()
MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY = -1
所有未觸發的執行都會立即執行,然後觸發器再按計劃運行。
.withMisfireHandlingInstructionFireAndProceed()
MISFIRE_INSTRUCTION_FIRE_ONCE_NOW = 1
立即執行第一個錯誤的執行並丟棄其他(即所有錯誤的執行合並在一起),也就是說無論錯過瞭多少次觸發器的執行,都隻會立即執行一次,然後觸發器再按計劃運行。(默認的失火策略)
.withMisfireHandlingInstructionDoNothing()
MISFIRE_INSTRUCTION_DO_NOTHING = 2
所有未觸發的執行都將被丟棄,然後再觸發器的下一個調度周期按計劃運行。
6、總結
關於quartz還有一個很重要的點就是corn表達式,這個個人認為沒必要死記硬背,實在不會寫的,上網找corn表達式在線轉換就可以瞭。
一個簡單demo的代碼地址:https://gitee.com/gorylee/quartz-demo
生產項目中quartz的配置使用代碼地址:https://gitee.com/gorylee/learnDemo/tree/master/quartzDemo
到此這篇關於springboot整合quartz項目使用(含完整代碼)的文章就介紹到這瞭,更多相關springboot整合quartz內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- SpringBoot2.6.3集成quartz的方式
- Java使用quartz實現定時任務示例詳解
- Spring Boot 配置 Quartz 定時任務的方法
- SpringBoot實現quartz定時任務可視化管理功能
- Java 任務調度框架 Quartz實操