Java中的任務調度框架quartz詳細解析
一、Quartz相關介紹
1.簡介
- Quartz 是一個完全由 Java 編寫的開源作業(yè)調度框架,為在 Java 應用程序中進行作業(yè)調度提供了簡單卻強大的機制。
- Quartz 可以與 J2EE 與 J2SE 應用程序相結合也可以單獨使用。
- Quartz 允許程序開發(fā)人員根據時間的間隔來調度作業(yè)。
- Quartz 實現了作業(yè)和觸發(fā)器的多對多的關系,還能把多個作業(yè)與不同的觸發(fā)器關聯。
2.Quartz 核心概念
我們需要明白 Quartz 的幾個核心概念,這樣理解起 Quartz 的原理就會變得簡單了。
- Job 表示一個工作,要執(zhí)行的具體內容。此接口中只有一個方法:void execute(JobExecutionContext context)
- JobDetail 表示一個具體的可執(zhí)行的調度程序,Job 是這個可執(zhí)行程調度程序所要執(zhí)行的內容,另外 JobDetail 還包含了這個任務調度的方案和策略。
- Trigger 代表一個調度參數的配置,什么時候去調。
- Scheduler 代表一個調度容器,一個調度容器中可以注冊多個 JobDetail 和 Trigger。當 Trigger 與 JobDetail 組合,就可以被 Scheduler 容器調度了。
項目層級
常見的幾種定時方法
線程休眠
先講個故事
一名程序員網友發(fā)帖曬出了自己寫的一段代碼,是一段定時代碼,根據他的語氣,可以看出他對自己寫的代碼感覺很好,是一段java代碼,好家伙,代碼中多線程都用上了,還有sleep,然后自己這樣寫了就直接被老板趕走了,走之前為了面子還說到,你這公司我還看不上呢,其實一想寫的確實沒問題功能能實現,但是
Java線程實現采用內核線程實現,線程的休眠及喚醒(狀態(tài)切換)需借助操作系統進行,這是一個極其耗時耗力的操作。在線程休眠或運行時間較長的情景下,其對性能的影響還不算明顯,因為對線程狀態(tài)的切換并不頻繁。但若線程休眠及運行的時間都很短(例如毫秒/秒,文中案例就是一個典型案例),系統將頻繁的對線程狀態(tài)進行切換,導致嚴重的性能損耗,并對著循環(huán)次數的遞增而放大。
所以是不推薦使用的!
/*** * 使用線程休眠實現定時任務,這種寫法是不建議寫的 */ public class Task01 { public static void main(String[] args) { Thread myThread = new Thread(new Runnable() { @Override public void run() { while (true) { System.out.println("TestThreadWait is called!"); try { // 使用線程休眠來實現周期執(zhí)行 Thread.sleep(1000 * 3); } catch (InterruptedException e) { e.printStackTrace(); } } } }); myThread.start(); } }
Timer
/*** * 延時任務 */ public class Task02 { public static void main(String[] args) { Timer timer = new Timer(); /*** * 參數一:需要執(zhí)行的任務 * 參數二:延遲多久 參數二不加只會執(zhí)行一次=定時任務 * 參數三,執(zhí)行的頻率 */ timer.schedule(new TimerTask() { @Override public void run() { System.out.println("使用timer實現定時任務"); } }, 0,1000); } }
通過ScheduledExecutorService實現定時任務
package com.changan.test; import com.sun.org.apache.bcel.internal.generic.NEW; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; /** * @program: springcloudalibaba * @description: * @author: Mr.shen * @create: 2022-06-27 09:35 **/ public class Task03 { public static void main(String[] args) { Runnable runnable= new Runnable() { @Override public void run() { System.out.println("通過ScheduledExecutorService實現定時任務"); } }; ScheduledExecutorService service= Executors.newSingleThreadScheduledExecutor(); service.scheduleAtFixedRate(runnable,1,2, TimeUnit.SECONDS); } }
進階
quartz(編寫觸發(fā)器和調度器 )
package com.changan.test; /** * @program: springcloudalibaba * @description: 編寫觸發(fā)器和調度器 * @author: Mr.shen * @create: 2022-06-27 10:28 **/ import com.changan.job.HelloJob; //import com.changan.test.service.HelloJob; import org.quartz.*; import org.quartz.impl.StdSchedulerFactory; public class HelloSchedulerDemo { public static void main(String[] args) throws Exception{ //1、調度器(Schedular),從工廠中獲取調度實例(默認:實例化new StdSchedulerFactory();) Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler(); //2、任務實例(JobDetail) JobDetail jobDetail= JobBuilder.newJob(HelloJob.class) //加載任務類,與HelloJob完成綁定,要求HelloJob實現Job接口 .withIdentity("job1","group1") //參數1:任務的名稱(唯一實例);參數2:任務組的名稱 .build(); //3、觸發(fā)器(Trigger) Trigger trigger= TriggerBuilder.newTrigger() .withIdentity("trigger1","group1") //參數1:觸發(fā)器的名稱(唯一實例);參數2:觸發(fā)器組的名稱 .startNow() //馬上啟動觸發(fā)器 .withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)) //每5秒執(zhí)行一次 .build(); //讓調度器關聯任務和觸發(fā)器,保證按照觸發(fā)器定義的條件執(zhí)行任務 scheduler.scheduleJob(jobDetail,trigger); //啟動 scheduler.start(); } }
job
package com.changan.job; /** * @program: springcloudalibaba * @description: 編寫一個Job類,用來編寫定時任務要做什么 * @author: Mr.shen * @create: 2022-06-27 10:25 **/ import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import java.text.SimpleDateFormat; import java.util.Date; public class HelloJob implements Job { public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { //輸出當前時間 Date date=new Date(); SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateString=dateFormat.format(date); //工作內容 System.out.println("執(zhí)行定時任務,時間是:"+dateString); } }
高階(使用springboot整合quartz并插入一條數據進入數據庫)
下面也需要用到CronExpression表達式
yaml
server: port: 8085 spring: application: name: quartz-service datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/tcw?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&zeroDateTimeBehavior=convertToNull username: root password: 123456 mybatis-plus: configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #?????? map-underscore-to-camel-case: true #??????? ????????create_time?????_?? mapper-locations: classpath*:/mapper/*Mapper.xml #???? type-aliases-package: com.changan.entity #??
- pom.xml
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <!-- mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies>
- 啟動器
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <!-- mybatis-plus--> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.1</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> </dependencies>
- Quartz配置類
package com.changan.config; import com.changan.adapter.MyadaptableJobFactory; import com.changan.job.QuartzDemo; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.CronTriggerFactoryBean; import org.springframework.scheduling.quartz.JobDetailFactoryBean; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; /** * @program: springcloudalibaba * @description: Quartz配置類 * @author: Mr.shen * @create: 2022-06-27 10:54 **/ @Configuration public class QuartzConfig { /** * 1、創(chuàng)建Job對象 */ @Bean public JobDetailFactoryBean jobDetailFactoryBean(){ JobDetailFactoryBean factoryBean=new JobDetailFactoryBean(); //關聯我們自己的Job類 factoryBean.setJobClass(QuartzDemo.class); //就是觸發(fā)這個定時任務執(zhí)行的任務 return factoryBean; } /** * 2、創(chuàng)建Trigger對象 */ @Bean public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){ CronTriggerFactoryBean factoryBean=new CronTriggerFactoryBean(); factoryBean.setJobDetail(jobDetailFactoryBean.getObject());//將任務代進去 factoryBean.setCronExpression("0/5 * * * * ?");//設置任務觸發(fā)條件 CronExpression表達式 return factoryBean; } /** * 3、創(chuàng)建Scheduler * 實現調度任務的配置 */ @Bean public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyadaptableJobFactory myadaptableJobFactory){ SchedulerFactoryBean factoryBean=new SchedulerFactoryBean(); factoryBean.setTriggers(cronTriggerFactoryBean.getObject()); factoryBean.setJobFactory(myadaptableJobFactory); return factoryBean; } }
- Job類(就是你時間到了觸發(fā)的方法)
package com.changan.job; import com.changan.entity.User; import com.changan.service.Userservice; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.beans.factory.annotation.Autowired; import java.util.Date; /** * @program: springcloudalibaba * @description: job類 * @author: Mr.shen * @create: 2022-06-27 10:40 **/ public class QuartzDemo implements Job { @Autowired private Userservice userService; @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { User user = new User(); user.setAge(12); user.setHead("dwwd"); user.setManager(123); user.setSex("dw"); user.setUpwd("wdwdw"); user.setUname("111"); System.out.println(userService.userinsert(user)); System.out.println("Execute..."+new Date()); } }
做完這些操作之后你運行插入你會發(fā)現Userservice并沒有注入bean 就算加service也不行下面就需要一個配置類了
- MyadaptableJobFactory(注入對象)
package com.changan.adapter; /** * @program: springcloudalibaba * @description: 編寫一個類MyAdaptableJobFactory繼承AdaptableJobFactory,覆蓋createJobInstance()方法。 * @author: Mr.shen * @create: 2022-06-27 10:54 **/ import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.scheduling.quartz.AdaptableJobFactory; import org.springframework.stereotype.Component; @Component("myadaptableJobFactory") //將該類實例化,使得可以直接用 public class MyadaptableJobFactory extends AdaptableJobFactory { //AutowireCapableBeanFactory可以將一個對象添加到Spring IOC容器中,并且完成該對象注入 @Autowired private AutowireCapableBeanFactory autowireCapableBeanFactory; //該方法將實例化的任務對象手動的添加到SpringIOC容器中并且完成對象的注入 @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { Object object = super.createJobInstance(bundle); //將object對象添加到Spring IOC容器中并完成注入 this.autowireCapableBeanFactory.autowireBean(object); return object; } }
到此這篇關于Java中的任務調度框架quartz詳細解析的文章就介紹到這了,更多相關Java任務調度框架quartz內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
使用SpringEvent解決WebUploader大文件上傳解耦問題
Spring Event是Spring框架內建的一種發(fā)布/訂閱模式的實現,它允許應用內部不同組件之間通過事件進行通信,本文以WebUploader大文件上傳組件為例,在大文件處理的場景中使用SpringEvent的事件發(fā)布機制,靈活的擴展對文件的處理需求,需要的朋友可以參考下2024-07-07Java隨機值設置(java.util.Random類或Math.random方法)
在編程中有時我們需要生成一些隨機的字符串作為授權碼、驗證碼等,以確保數據的安全性和唯一性,這篇文章主要給大家介紹了關于Java隨機值設置的相關資料,主要用的是java.util.Random類或Math.random()方法,需要的朋友可以參考下2024-08-08JAVA實現 SpringMVC方式的微信接入、實現簡單的自動回復功能
這篇文章主要介紹了JAVA實現 SpringMVC方式的微信接入、實現簡單的自動回復功能的相關資料,非常不錯具有參考借鑒價值,需要的朋友可以參考下2016-11-11