Java中的任務(wù)調(diào)度框架quartz詳細(xì)解析
一、Quartz相關(guān)介紹
1.簡(jiǎn)介
- Quartz 是一個(gè)完全由 Java 編寫(xiě)的開(kāi)源作業(yè)調(diào)度框架,為在 Java 應(yīng)用程序中進(jìn)行作業(yè)調(diào)度提供了簡(jiǎn)單卻強(qiáng)大的機(jī)制。
- Quartz 可以與 J2EE 與 J2SE 應(yīng)用程序相結(jié)合也可以單獨(dú)使用。
- Quartz 允許程序開(kāi)發(fā)人員根據(jù)時(shí)間的間隔來(lái)調(diào)度作業(yè)。
- Quartz 實(shí)現(xiàn)了作業(yè)和觸發(fā)器的多對(duì)多的關(guān)系,還能把多個(gè)作業(yè)與不同的觸發(fā)器關(guān)聯(lián)。
2.Quartz 核心概念
我們需要明白 Quartz 的幾個(gè)核心概念,這樣理解起 Quartz 的原理就會(huì)變得簡(jiǎn)單了。
- Job 表示一個(gè)工作,要執(zhí)行的具體內(nèi)容。此接口中只有一個(gè)方法:void execute(JobExecutionContext context)
- JobDetail 表示一個(gè)具體的可執(zhí)行的調(diào)度程序,Job 是這個(gè)可執(zhí)行程調(diào)度程序所要執(zhí)行的內(nèi)容,另外 JobDetail 還包含了這個(gè)任務(wù)調(diào)度的方案和策略。
- Trigger 代表一個(gè)調(diào)度參數(shù)的配置,什么時(shí)候去調(diào)。
- Scheduler 代表一個(gè)調(diào)度容器,一個(gè)調(diào)度容器中可以注冊(cè)多個(gè) JobDetail 和 Trigger。當(dāng) Trigger 與 JobDetail 組合,就可以被 Scheduler 容器調(diào)度了。
項(xiàng)目層級(jí)

常見(jiàn)的幾種定時(shí)方法
線(xiàn)程休眠
先講個(gè)故事
一名程序員網(wǎng)友發(fā)帖曬出了自己寫(xiě)的一段代碼,是一段定時(shí)代碼,根據(jù)他的語(yǔ)氣,可以看出他對(duì)自己寫(xiě)的代碼感覺(jué)很好,是一段java代碼,好家伙,代碼中多線(xiàn)程都用上了,還有sleep,然后自己這樣寫(xiě)了就直接被老板趕走了,走之前為了面子還說(shuō)到,你這公司我還看不上呢,其實(shí)一想寫(xiě)的確實(shí)沒(méi)問(wèn)題功能能實(shí)現(xiàn),但是
Java線(xiàn)程實(shí)現(xiàn)采用內(nèi)核線(xiàn)程實(shí)現(xiàn),線(xiàn)程的休眠及喚醒(狀態(tài)切換)需借助操作系統(tǒng)進(jìn)行,這是一個(gè)極其耗時(shí)耗力的操作。在線(xiàn)程休眠或運(yùn)行時(shí)間較長(zhǎng)的情景下,其對(duì)性能的影響還不算明顯,因?yàn)閷?duì)線(xiàn)程狀態(tài)的切換并不頻繁。但若線(xiàn)程休眠及運(yùn)行的時(shí)間都很短(例如毫秒/秒,文中案例就是一個(gè)典型案例),系統(tǒng)將頻繁的對(duì)線(xiàn)程狀態(tài)進(jìn)行切換,導(dǎo)致嚴(yán)重的性能損耗,并對(duì)著循環(huán)次數(shù)的遞增而放大。
所以是不推薦使用的!
/***
* 使用線(xiàn)程休眠實(shí)現(xiàn)定時(shí)任務(wù),這種寫(xiě)法是不建議寫(xiě)的
*/
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 {
// 使用線(xiàn)程休眠來(lái)實(shí)現(xiàn)周期執(zhí)行
Thread.sleep(1000 * 3);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
myThread.start();
}
}
Timer
/***
* 延時(shí)任務(wù)
*/
public class Task02 {
public static void main(String[] args) {
Timer timer = new Timer();
/***
* 參數(shù)一:需要執(zhí)行的任務(wù)
* 參數(shù)二:延遲多久 參數(shù)二不加只會(huì)執(zhí)行一次=定時(shí)任務(wù)
* 參數(shù)三,執(zhí)行的頻率
*/
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("使用timer實(shí)現(xiàn)定時(shí)任務(wù)");
}
}, 0,1000);
}
}
通過(guò)ScheduledExecutorService實(shí)現(xiàn)定時(shí)任務(wù)
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("通過(guò)ScheduledExecutorService實(shí)現(xiàn)定時(shí)任務(wù)");
}
};
ScheduledExecutorService service= Executors.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(runnable,1,2, TimeUnit.SECONDS);
}
}
進(jìn)階
quartz(編寫(xiě)觸發(fā)器和調(diào)度器 )
package com.changan.test;
/**
* @program: springcloudalibaba
* @description: 編寫(xiě)觸發(fā)器和調(diào)度器
* @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、調(diào)度器(Schedular),從工廠中獲取調(diào)度實(shí)例(默認(rèn):實(shí)例化new StdSchedulerFactory();)
Scheduler scheduler= StdSchedulerFactory.getDefaultScheduler();
//2、任務(wù)實(shí)例(JobDetail)
JobDetail jobDetail= JobBuilder.newJob(HelloJob.class) //加載任務(wù)類(lèi),與HelloJob完成綁定,要求HelloJob實(shí)現(xiàn)Job接口
.withIdentity("job1","group1") //參數(shù)1:任務(wù)的名稱(chēng)(唯一實(shí)例);參數(shù)2:任務(wù)組的名稱(chēng)
.build();
//3、觸發(fā)器(Trigger)
Trigger trigger= TriggerBuilder.newTrigger()
.withIdentity("trigger1","group1") //參數(shù)1:觸發(fā)器的名稱(chēng)(唯一實(shí)例);參數(shù)2:觸發(fā)器組的名稱(chēng)
.startNow() //馬上啟動(dòng)觸發(fā)器
.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)) //每5秒執(zhí)行一次
.build();
//讓調(diào)度器關(guān)聯(lián)任務(wù)和觸發(fā)器,保證按照觸發(fā)器定義的條件執(zhí)行任務(wù)
scheduler.scheduleJob(jobDetail,trigger);
//啟動(dòng)
scheduler.start();
}
}
job
package com.changan.job;
/**
* @program: springcloudalibaba
* @description: 編寫(xiě)一個(gè)Job類(lèi),用來(lái)編寫(xiě)定時(shí)任務(wù)要做什么
* @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 {
//輸出當(dāng)前時(shí)間
Date date=new Date();
SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateString=dateFormat.format(date);
//工作內(nèi)容
System.out.println("執(zhí)行定時(shí)任務(wù),時(shí)間是:"+dateString);
}
}
高階(使用springboot整合quartz并插入一條數(shù)據(jù)進(jìn)入數(shù)據(jù)庫(kù))
下面也需要用到CronExpression表達(dá)式
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>
- 啟動(dòng)器
<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配置類(lèi)
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配置類(lèi)
* @author: Mr.shen
* @create: 2022-06-27 10:54
**/
@Configuration
public class QuartzConfig {
/**
* 1、創(chuàng)建Job對(duì)象
*/
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();
//關(guān)聯(lián)我們自己的Job類(lèi)
factoryBean.setJobClass(QuartzDemo.class); //就是觸發(fā)這個(gè)定時(shí)任務(wù)執(zhí)行的任務(wù)
return factoryBean;
}
/**
* 2、創(chuàng)建Trigger對(duì)象
*/
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
CronTriggerFactoryBean factoryBean=new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetailFactoryBean.getObject());//將任務(wù)代進(jìn)去
factoryBean.setCronExpression("0/5 * * * * ?");//設(shè)置任務(wù)觸發(fā)條件 CronExpression表達(dá)式
return factoryBean;
}
/**
* 3、創(chuàng)建Scheduler
* 實(shí)現(xiàn)調(diào)度任務(wù)的配置
*/
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyadaptableJobFactory myadaptableJobFactory){
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
factoryBean.setJobFactory(myadaptableJobFactory);
return factoryBean;
}
}
- Job類(lèi)(就是你時(shí)間到了觸發(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類(lèi)
* @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());
}
}
做完這些操作之后你運(yùn)行插入你會(huì)發(fā)現(xiàn)Userservice并沒(méi)有注入bean 就算加service也不行下面就需要一個(gè)配置類(lèi)了
- MyadaptableJobFactory(注入對(duì)象)
package com.changan.adapter;
/**
* @program: springcloudalibaba
* @description: 編寫(xiě)一個(gè)類(lèi)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") //將該類(lèi)實(shí)例化,使得可以直接用
public class MyadaptableJobFactory extends AdaptableJobFactory {
//AutowireCapableBeanFactory可以將一個(gè)對(duì)象添加到Spring IOC容器中,并且完成該對(duì)象注入
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
//該方法將實(shí)例化的任務(wù)對(duì)象手動(dòng)的添加到SpringIOC容器中并且完成對(duì)象的注入
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object object = super.createJobInstance(bundle);
//將object對(duì)象添加到Spring IOC容器中并完成注入
this.autowireCapableBeanFactory.autowireBean(object);
return object;
}
}
到此這篇關(guān)于Java中的任務(wù)調(diào)度框架quartz詳細(xì)解析的文章就介紹到這了,更多相關(guān)Java任務(wù)調(diào)度框架quartz內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用Servlet Filter實(shí)現(xiàn)系統(tǒng)登錄權(quán)限
這篇文章主要為大家詳細(xì)介紹了使用Servlet Filter實(shí)現(xiàn)系統(tǒng)登錄權(quán)限,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
SpringBoot整合HikariCP數(shù)據(jù)庫(kù)連接池方式
這篇文章主要介紹了SpringBoot整合HikariCP數(shù)據(jù)庫(kù)連接池方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-03-03
Java線(xiàn)程本地變量導(dǎo)致的緩存問(wèn)題解決方法
使用緩存可以緩解大流量壓力,顯著提高程序的性能,我們?cè)谑褂镁彺嫦到y(tǒng)時(shí),尤其是大并發(fā)情況下,經(jīng)常會(huì)遇到一些疑難雜癥,這篇文章主要給大家介紹了關(guān)于Java線(xiàn)程本地變量導(dǎo)致的緩存問(wèn)題的解決方法,需要的朋友可以參考下,2024-08-08
Spring?boot?整合?Redisson實(shí)現(xiàn)分布式鎖并驗(yàn)證功能
這篇文章主要介紹了Spring?boot?整合?Redisson實(shí)現(xiàn)分布式鎖并驗(yàn)證,redisson是官方推薦的分布式鎖實(shí)現(xiàn)方案,采用redis自身的原子命令和lua腳本來(lái)實(shí)現(xiàn),需要的朋友可以參考下2022-05-05
關(guān)于Jmeter接口測(cè)試實(shí)戰(zhàn)-Cookies
這篇文章主要介紹了關(guān)于Jmeter接口測(cè)試實(shí)戰(zhàn)-Cookies問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
HelloSpringMVC配置版實(shí)現(xiàn)步驟解析
這篇文章主要介紹了HelloSpringMVC配置版實(shí)現(xiàn)步驟解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09
Java中用爬蟲(chóng)進(jìn)行解析的實(shí)例方法
在本篇文章里小編給大家整理的是一篇關(guān)于Java中用爬蟲(chóng)進(jìn)行解析的實(shí)例方法,有需要的朋友們可以學(xué)習(xí)參考下。2020-12-12
Spring定時(shí)服務(wù)QuartZ原理及代碼案例
這篇文章主要介紹了Spring定時(shí)服務(wù)QuartZ原理及代碼案例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
java利用mybatis攔截器統(tǒng)計(jì)sql執(zhí)行時(shí)間示例
這篇文章主要介紹了java利用mybatis攔截器統(tǒng)計(jì)sql執(zhí)行時(shí)間示例,該攔截器攔截mybatis的query和update操作,能統(tǒng)計(jì)sql執(zhí)行時(shí)間2014-03-03
java實(shí)現(xiàn)從url路徑中下載pdf文檔到本地
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)從url路徑中下載pdf文檔到本地,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以了解下2025-11-11

