国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當前位置: 首頁 > news >正文

動態(tài)網(wǎng)站開發(fā)平臺簡介什么叫seo

動態(tài)網(wǎng)站開發(fā)平臺簡介,什么叫seo,深圳建網(wǎng)站興田德潤可信,有關大學生做兼職的網(wǎng)站第一章 定時任務概述 在項目中開發(fā)定時任務應該一種比較常見的需求,在 Java 中開發(fā)定時任務主要有三種解決方案:一是使用JDK 自帶的 Timer,二是使用 Spring Task,三是使用第三方組件 Quartz Timer 是 JDK 自帶的定時任務工具,其…

第一章 定時任務概述

在項目中開發(fā)定時任務應該一種比較常見的需求,在 Java 中開發(fā)定時任務主要有三種解決方案:一是使用JDK 自帶的 Timer,二是使用 Spring Task,三是使用第三方組件 Quartz

Timer 是 JDK 自帶的定時任務工具,其簡單易用,但是對于復雜的定時規(guī)則無法滿足,在實際項目開發(fā)中也很少使用到。而 Spring Task使用起來很簡單,除 Spring 相關的包外不需要額外的包,而且支持注解和配置文件兩種形式。 Quartz 功能強大,但是使用起來相對笨重。

建議:

  • 單體項目架構使用Spring Task

  • 分布式項目架構使用Quartz

第二章 JDK實現(xiàn)任務調度

/*** 基于jdk的任務調度*/
public class JdkTaskDemo {public static void main(String[] args) {//創(chuàng)建定時類Timer timer = new Timer();//創(chuàng)建任務類TimerTask task = new TimerTask() {@Overridepublic void run() {System.out.println("定時任務執(zhí)行了......"+ LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));}};//執(zhí)行定時任務timer.schedule(task,new Date(),2000);}
}

第三章 Spring-task實現(xiàn)任務調度

3.1 節(jié) Spring-task入門案例

【1】搭建SpringBoot工程,導入spring-boot-starter-web即可,不需導入任何其他依賴,pom如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>top.psjj</groupId><artifactId>task-study</artifactId><version>0.0.1-SNAPSHOT</version><name>task-study</name><description>task-study</description><properties><java.version>8</java.version></properties><dependencies><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><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

【2】編寫啟動類,打開任務調度注解

package top.psjj;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class TaskStudyApplication {public static void main(String[] args) {SpringApplication.run(TaskStudyApplication.class, args);}
}

【3】編寫任務類測試

//創(chuàng)建測試任務類//放入容器中
@Component
public class SpringTask {//使用@Scheduled 注解 配合 cron 表達式@Scheduled(cron = "*/1 * * * * *")public void task1() throws  InterruptedException {System.out.println(Thread.currentThread().getName()+"task1-->"+LocalDateTime.now());}
}

3.2 節(jié) Spring-task 分析

接下來,我們編寫任務調度,可調度程序加一下執(zhí)行時間,模擬真實業(yè)務。

//創(chuàng)建測試任務類//放入容器中
@Component
public class SpringTask {//使用@Scheduled 注解 配合 cron 表達式@Scheduled(cron = "*/1 * * * * *")public void task1() throws  InterruptedException {System.out.println(Thread.currentThread().getName()+"task1-->"+LocalDateTime.now());Thread.sleep(5000);}
}

任務并不是每秒執(zhí)行一次,而是六秒執(zhí)行一次

得出結論:

1.Spring-task 執(zhí)行任務按照單線程執(zhí)行并合理執(zhí)行,不會因為第一個執(zhí)行任務時間過長而去執(zhí)行第二個任務

2.Spring-task是單線程的處理任務,處理任務能力有限,不建議處理分布式架構的任務調度

比如說:

@Component
public class MyTask {@Scheduled(cron = "*/1 * * * * *") //每秒執(zhí)行1次public void task2() throws InterruptedException {System.out.println(Thread.currentThread().getName()+":task2--->"+ LocalDateTime.now());}@Scheduled(cron = "*/1 * * * * *") //每秒執(zhí)行1次public void task1() throws InterruptedException {System.out.println(Thread.currentThread().getName()+":task1--->"+ LocalDateTime.now());Thread.sleep(5000);}
}

定時任務2 1s時間執(zhí)行完但受任務1影響也需要等5s。 ?

3.3 節(jié) Cron表達式講解

關于 cronExpression 表達式有至少 6 個(也可能是 7 個)由空格分隔的時間元素。從左至右,這些元素的定義如下:

1.秒(0–59)

2.分鐘(0–59)

3.小時(0–23)

4.月份中的日期(1–31)

5.月份(1–12 或 JAN–DEC)

6.星期中的日期(1–7 或 SUN–SAT)

7.年份(1970–2099)

逗號為并列作用

0 0 10,14,16 * * ? 每天上午 10 點,下午 2 點和下午 4 點 

- 是代表1到10天?

0 0,15,30,45 * 1-10 * ? 每月前 10 天每隔 15 分鐘 
30 0 0 1 1 ? 2012 在 2012 年 1 月 1 日午夜過 30 秒時 

各個時間可用值如下:

秒 0-59 , - * /

分 0-59 , - * /

小時 0-23 , - * /

日 1-31 , - * ? / L W C

月 1-12 or JAN-DEC , - * /

周幾 1-7 or SUN-SAT , - * ? / L C #

年(可選字段) empty, 1970-2099 , - * /

可用值詳細分析如下:

"*" —— 字符可以用于所有字段,在"分"字段中設為"*",表示"每一分鐘"的含義。
"?" —— 字符可以用在"日"和"周幾"字段,它用來指定"不明確的值"。這在你需要指定這兩個字段中的某一個值而不是另外一個的時候會被用到。在后面的例子中可以看到其含義。
"-" —— 字符被用來指定一個值的范。比如在"小時"字段中設為"10-12",表示"10 點到 12 點"。 
"," —— 字符指定數(shù)個值。比如在"周幾"字段中設為"MON,WED,FRI",表示"the days Monday, Wednesday, and Friday"。 
"/" —— 字符用來指定一個值的的增加幅度。比如在"秒"字段中設置為"0/15"表示"第 0, 15, 30,和 45 秒"。而"5/15"則表示"第 5, 20, 35,和 50"。在'/'前加"*"字符相當于指定從 0 秒開始。每個字段都有一系列可以開始或結束的數(shù)值。對于"秒"和"分"字段來說,其數(shù)值范圍為 0 到 59。對于"小時"字段來說其為 0 到 23,對于“日”字段來說為 0 到 31。而對于"月"字段來說為 1 到 12。"/"字段僅僅只是幫助你在允許的數(shù)值范圍內從開始"第 n"的值。
"L" —— 字符可用在"日"和"周幾"這兩個字段。它是"last"的縮寫,但是在這兩個字段中有不同的含義。"日"字段中的"L"表示"一個月中的最后一天",對于一月就是 31 號,對于二月來說就是 28 號(非閏年)。"周幾"字段中,它簡單的表示"7" or "SAT"。但是如果在"周幾"字段中使用時跟在某個數(shù)字之后,它表示"該月最后一個星期×"。比如"6L"表示"該月最后一個周五"。當使用"L"選項時,指定確定的列表或者范圍非常重要,否則你會被結果搞糊涂的。
"W" —— 可用于"日"字段。用來指定歷給定日期最近的工作日(周一到周五)。比如將"日"字段設為"15W",意為: "離該月 15 號最近的工作日"。因此如果 15 號為周六,觸發(fā)器會在 14 號即周五調用。如果 15 號為周日,觸發(fā)器會在 16 號也就是周一觸發(fā)。如果 15 號為周二,那么當天就會觸發(fā)。如果"日"字段設為"1W",而一號是周六,會于下周一即當月的 3 號觸發(fā),它不會越過當月的值的范圍邊界。"W"字符只能用于"日"字段的值為單獨的一天而不是一系列值的時候。"L"和"W"可以組合用于“日”字段表示為'LW',意為"該月最后一個工作日"。 
"#" —— 字符可用于"周幾"字段。該字符表示"該月第幾個周×"。比如"6#3"表示該月第三個周五( 6 表示周五,而"#3"該月第三個)。再比如: "2#1" 表示該月第一個周一,而"4#5" 該月第五個周三。注意如果你指定"#5"該月沒有第五個"周×",該月是不會觸發(fā)的。
"C" —— 字符可用于"日"和"周幾"字段,它是"calendar"的縮寫。它表示為基于相關的日歷所計算出的值(如果有)。如果沒有關聯(lián)的日歷,那它等同于包含全部日歷。"日"字段值為"5C",表示"日歷中的第一天或者 5 號以后"。"周幾"字段值為"1C",則表示"日歷中的第一天或者周日以后"。對于"月份"字段和"周幾"字段來說合法的字符都不是大小寫敏感的。

備注:以上讀一遍有印象即可,實際開發(fā)在線文檔自動生成

在線Cron表達式生成器

第四章 Quartz 基本應用

4.1 節(jié) Quartz 介紹

Quartz是OpenSymphony開源組織在Job scheduling領域又一個開源項目,完全由Java開發(fā),可以用來執(zhí)行定時任務,類似于java.util.Timer。但是相較于Timer, Quartz增加了很多功能:

  • 持久性作業(yè) - 就是保持調度定時的狀態(tài);

  • 作業(yè)管理 - 對調度作業(yè)進行有效的管理;

官方文檔:

  • Documentation

  • Quartz Enterprise Job Scheduler 2.3.0-SNAPSHOT API

4.2 節(jié) Quartz API 介紹

?Quartz 的核心類有以下三部分:

  • 任務Job: 需要實現(xiàn)的任務類,實現(xiàn)execute()方法,執(zhí)行后完成任務
  • 觸發(fā)器Trigger :包括SimpleTrigger 和 CronTrigger
  • 調度器Scheduler:任務調度器,負責基于Trigger觸發(fā)器,來執(zhí)行job任務

4.3 節(jié) Quartz 入門案例

1)創(chuàng)建springboot工程,導入依賴

pom如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>top.psjj</groupId><artifactId>quartz-study</artifactId><version>0.0.1-SNAPSHOT</version><name>quartz-study</name><description>quartz-study</description><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2)新建任務類

public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("任務被執(zhí)行了");}
}

3)創(chuàng)建調度器、jobDetail 實例、trigger 實例、執(zhí)行

public class QuartzTest {public static void main(String[] args) throws SchedulerException {//1.創(chuàng)建任務調度器SchedulerFactory factory = new StdSchedulerFactory();Scheduler scheduler = factory.getScheduler();//2.創(chuàng)建JobDetail實例,并與MyJob類綁定JobDetail job = JobBuilder.newJob(MyJob.class)//指定任務名,組名.withIdentity("job1","group1").build();//3.構建Trigger實例,每隔3s執(zhí)行一次Trigger trigger = TriggerBuilder.newTrigger()//指定觸發(fā)器名字,組名.withIdentity("trigger1","group1")//從現(xiàn)在觸發(fā).startNow()//觸發(fā)規(guī)則3s觸發(fā)一次.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever()).build();//4.執(zhí)行 開啟任務調度器scheduler.scheduleJob(job,trigger);System.out.println(System.currentTimeMillis());scheduler.start();}
}

4)測試結果

每3s執(zhí)行一次

第五章 QuartzAPI詳細講解

5.1 節(jié) JobDetail

JobDetail 的作用是綁定 Job,是一個任務實例,它為 Job 添加了許多擴展參數(shù)。

主要字段含義
name任務名稱
group任務分組,默認分組DEFAULT
jobClass要執(zhí)行的Job實現(xiàn)類
jobDataMap任務參數(shù)信息,JobDetail、Trigger都可以使用JobDataMap來設置一些參數(shù)或者信息

每次Scheduler調度執(zhí)行一個Job的時候,首先會拿到對應的Job,然后創(chuàng)建該Job實例,再去執(zhí)行Job中的execute()的內容,任務執(zhí)行結束后,關聯(lián)的Job對象實例會被釋放,且會被JVM GC清除。

為什么設計成JobDetail + Job,不直接使用Job?

JobDetail 定義的是任務數(shù)據(jù),而真正的執(zhí)行邏輯是在Job中。

這是因為任務是有可能并發(fā)執(zhí)行,如果Scheduler直接使用Job,就會存在對同一個Job實例并發(fā)訪問的問題。

JobDetail & Job 方式,Sheduler每次執(zhí)行,都會根據(jù)JobDetail創(chuàng)建一個新的Job實例,這樣就可以 規(guī)避并發(fā)訪問 的問題。

攜帶參數(shù)案例

package com.sh;import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.scheduling.annotation.Scheduled;/*** @Auther: 世豪講java* @Date: 2024/1/4 - 01 - 04 - 20:27* @Decsription: com.sh* @version: 1.0*/
public class QuartzTest {//test方法之后執(zhí)行一次,所以使用main方法public static void main(String[] args) throws SchedulerException {//1.創(chuàng)建任務調度器SchedulerFactory factory = new StdSchedulerFactory();Scheduler scheduler = factory.getScheduler();//創(chuàng)建JobDataMap,可攜帶的參數(shù)JobDataMap jobDataMap = new JobDataMap();jobDataMap.put("param1","value1");jobDataMap.put("param2","value2");//2.創(chuàng)建JobDetail實例,與MyJob類綁定JobDetail job = JobBuilder.newJob(MyJob.class)//指定任務名,組名.withIdentity("job1","group1")//攜帶參數(shù)JobDataMap.setJobData(jobDataMap).build();//3.構建Trigger實例,每個3s執(zhí)行一次Trigger trigger = TriggerBuilder.newTrigger()//指定觸發(fā)器名字,組名.withIdentity("trigger1","group1")//什么時候觸發(fā).startNow()//觸發(fā)規(guī)則,3秒觸發(fā)一次//簡單的SimpleScheduleBuilder構建起.withSchedule(SimpleScheduleBuilder.simpleSchedule()//每3s觸發(fā)一次.withIntervalInSeconds(3)//永遠觸發(fā).repeatForever()).build();//4.調度器執(zhí)行任務//把job和trigger給schedulescheduler.scheduleJob(job,trigger);System.out.println(System.currentTimeMillis());//啟動任務scheduler.start();}
}
public class MyJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {//獲取jobDataMapJobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();System.out.println("任務被執(zhí)行了"+jobDataMap.get("param1")+jobDataMap.get("param2"));}
}

5.2 節(jié) SimpleTrigger

這是比較簡單的一類觸發(fā)器,用它能實現(xiàn)很多基礎的應用。使用它的主要場景包括:

  • 在指定時間段內,執(zhí)行一次任務

最基礎的 Trigger 不設置循環(huán),設置開始時間。

  • 在指定時間段內,循環(huán)執(zhí)行任務

在 1 基礎上加上循環(huán)間隔??梢灾付?永遠循環(huán)、運行指定次數(shù)

示例:

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger2","group1").startNow().withSchedule(//使用簡單觸發(fā)器SimpleScheduleBuilder.simpleSchedule().//3s間隔執(zhí)行withIntervalInSeconds(3).//執(zhí)行6次 count+1withRepeatCount(5)).build();

5.3 節(jié) CronTrigger

CronTrigger 是基于日歷的任務調度器,在實際應用中更加常用。雖然很常用,但是知識點都一樣,只是可以通過表達式來設置時間而已。使用方式就是綁定調度器時換一下:

Trigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger2","group1").startNow().withSchedule(//使用日歷觸發(fā)器CronScheduleBuilder.cronSchedule("0/1 * * * * ? ")).build();

第六章 SpringBoot整合Quartz

6.1 節(jié) SpringBoot整合Quartz

接下來實現(xiàn)SpringBoot整合Quartz動態(tài)實現(xiàn)任務調度;動態(tài)任務調度ui參考

該UI需要自己創(chuàng)建

1)添加依賴 ?

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.7.6</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>top.psjj</groupId><artifactId>quartz-study</artifactId><version>0.0.1-SNAPSHOT</version><name>quartz-study</name><description>quartz-study</description><properties><java.version>8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.26</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.60</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>

2)編寫application.yml配置文件,內容如下

server:port: 80
spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverusername: rootpassword: 123456url: jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai# 定時配置quartz:# 相關屬性配置properties:org:quartz:# 數(shù)據(jù)源dataSource:globalJobDataSource:# URL必須大寫URL: jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghaidriver: com.mysql.cj.jdbc.DrivermaxConnections: 5username: rootpassword: 123456# 必須指定數(shù)據(jù)源類型provider: hikaricpscheduler:instanceName: globalScheduler# 實例idinstanceId: AUTOtype: com.alibaba.druid.pool.DruidDataSourcejobStore:# 數(shù)據(jù)源dataSource: globalJobDataSource# JobStoreTX將用于獨立環(huán)境,提交和回滾都將由這個類處理class: org.quartz.impl.jdbcjobstore.JobStoreTX# 驅動配置driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate# 表前綴tablePrefix: QRTZ_# 失效閾值(只有配置了這個時間,超時策略根據(jù)這個時間才有效)misfireThreshold: 100# 集群配置isClustered: true# 線程池配置threadPool:class: org.quartz.simpl.SimpleThreadPool# 線程數(shù)threadCount: 10# 優(yōu)先級threadPriority: 5

這里面有quartz的數(shù)據(jù)源,線程池,集群和misfire相關配置,簡單配置,更多的配置可以到官網(wǎng)查看。

Configuration Reference

配置application.properties 自動生成表

只需要執(zhí)行一次,再次執(zhí)行會重置表中數(shù)據(jù),影響實際業(yè)務

spring.quartz.jdbc.initialize-schema: always
spring.quartz.job-store-type: jdbc

3)實體類

@Data
public class JobInfo {/*** 任務名稱*/private String jobName;/*** 任務組*/private String jobGroup;/*** 觸發(fā)器名稱*/private String triggerName;/*** 觸發(fā)器組*/private String triggerGroup;/*** cron表達式*/private String cron;/*** 類名*/private String className;/*** 狀態(tài)*/private String status;/*** 下一次執(zhí)行時間*/private String nextTime;/*** 上一次執(zhí)行時間*/private String prevTime;/*** 配置信息(data)*/private String config;
}

4)任務類

 * @DisallowConcurrentExecution:這個注解的作用就是同一個任務必須在上一次執(zhí)行完畢之后,再按照corn時間執(zhí)行,不會并行執(zhí)行* @PersistJobDataAfterExecution:這個注解的作用就是下一個任務用到上一個任務的修改數(shù)據(jù)(定時任務里面的jobData數(shù)據(jù)流轉)*/@DisallowConcurrentExecution
@PersistJobDataAfterExecution
@Slf4j
@Component
public class MyTask extends QuartzJobBean {@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {System.out.println("任務1正在執(zhí)行..." + LocalDateTime.now());// 執(zhí)行9秒try {Thread.sleep(9000);System.out.println("任務1執(zhí)行完畢..." + LocalDateTime.now());} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

這個類就是繼承的QuartzJobBean,當然也可以實現(xiàn)Job接口,這個類就是任務需要具體執(zhí)行的業(yè)務操作類,類上面添加了兩個注解,這兩個注解的目的就是讓同一個任務必須在上一個任務執(zhí)行完畢之后再按照觸發(fā)后續(xù)執(zhí)行,以及定時任務里面的JobDataMap,能夠在任務中流轉以及修改更新;不添加注解的情況下,JobDataMap里面的數(shù)據(jù)不能在任務之間流轉,以及任務的觸發(fā)不會參照上一任務是否執(zhí)行完畢。

5)JobHandle(任務的開關停刪操作)

@Configuration
public class JobHandler {@Resourceprivate Scheduler scheduler;/*** 添加任務*/@SuppressWarnings("unchecked")public void addJob(JobInfo jobInfo) throws SchedulerException, ClassNotFoundException {Objects.requireNonNull(jobInfo, "任務信息不能為空");// 生成job keyJobKey jobKey = JobKey.jobKey(jobInfo.getJobName(), jobInfo.getJobGroup());// 當前任務不存在才進行添加if (!scheduler.checkExists(jobKey)) {Class<Job> jobClass = (Class<Job>)Class.forName(jobInfo.getClassName());// 任務明細JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobKey).withIdentity(jobInfo.getJobName(), jobInfo.getJobGroup()).withDescription(jobInfo.getJobName()).build();// 配置信息jobDetail.getJobDataMap().put("config", jobInfo.getConfig());// 定義觸發(fā)器TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getTriggerName(), jobInfo.getTriggerGroup());// 設置任務的錯過機制Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey).withSchedule(CronScheduleBuilder.cronSchedule(jobInfo.getCron()).withMisfireHandlingInstructionDoNothing()).build();scheduler.scheduleJob(jobDetail, trigger);} else {throw new SchedulerException(jobInfo.getJobName() + "任務已存在,無需重復添加");}}/*** 任務暫停*/public void pauseJob(String jobGroup, String jobName) throws SchedulerException {JobKey jobKey = JobKey.jobKey(jobName, jobGroup);if (scheduler.checkExists(jobKey)) {scheduler.pauseJob(jobKey);}}/*** 繼續(xù)任務*/public void continueJob(String jobGroup, String jobName) throws SchedulerException {JobKey jobKey = JobKey.jobKey(jobName, jobGroup);if (scheduler.checkExists(jobKey)) {scheduler.resumeJob(jobKey);}}/*** 刪除任務*/public boolean deleteJob(String jobGroup, String jobName) throws SchedulerException {JobKey jobKey = JobKey.jobKey(jobName, jobGroup);if (scheduler.checkExists(jobKey)) {// 這里還需要先刪除trigger相關//TriggerKey triggerKey = TriggerKey.triggerKey(jobInfo.getTriggerName(), jobInfo.getTriggerGroup());//scheduler.getTrigger()//scheduler.rescheduleJob()return scheduler.deleteJob(jobKey);}return false;}/*** 獲取任務信息*/public JobInfo getJobInfo(String jobGroup, String jobName) throws SchedulerException {JobKey jobKey = JobKey.jobKey(jobName, jobGroup);if (!scheduler.checkExists(jobKey)) {return null;}List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);if (Objects.isNull(triggers)) {throw new SchedulerException("未獲取到觸發(fā)器信息");}TriggerKey triggerKey = triggers.get(0).getKey();Trigger.TriggerState triggerState = scheduler.getTriggerState(triggerKey);JobDetail jobDetail = scheduler.getJobDetail(jobKey);JobInfo jobInfo = new JobInfo();jobInfo.setJobName(jobGroup);jobInfo.setJobGroup(jobName);jobInfo.setTriggerName(triggerKey.getName());jobInfo.setTriggerGroup(triggerKey.getGroup());jobInfo.setClassName(jobDetail.getJobClass().getName());jobInfo.setStatus(triggerState.toString());if (Objects.nonNull(jobDetail.getJobDataMap())) {jobInfo.setConfig(JSONObject.toJSONString(jobDetail.getJobDataMap()));}CronTrigger theTrigger = (CronTrigger) triggers.get(0);jobInfo.setCron(theTrigger.getCronExpression());return jobInfo;}
}

6)Controller(調用接口實現(xiàn)任務操作)

@RestController
@RequestMapping("/job")
public class QuartzController {@Resourceprivate JobHandler jobHandler;@Resourceprivate Scheduler scheduler;/*** 查詢所有的任務*/@RequestMapping("/all")public List<JobInfo> list() throws SchedulerException {List<JobInfo> jobInfos = new ArrayList<>();List<String> triggerGroupNames = scheduler.getTriggerGroupNames();for (String triggerGroupName : triggerGroupNames) {Set<TriggerKey> triggerKeySet = scheduler.getTriggerKeys(GroupMatcher.triggerGroupEquals(triggerGroupName));for (TriggerKey triggerKey : triggerKeySet) {Trigger trigger = scheduler.getTrigger(triggerKey);JobKey jobKey = trigger.getJobKey();JobInfo jobInfo = jobHandler.getJobInfo(jobKey.getGroup(), jobKey.getName());jobInfos.add(jobInfo);}}return jobInfos;}/*** 添加任務*/@PostMapping("/add")public JobInfo addJob(@RequestBody JobInfo jobInfo) throws SchedulerException, ClassNotFoundException {jobHandler.addJob(jobInfo);return jobInfo;}/*** 暫停任務*/@RequestMapping("/pause")public void pauseJob(@RequestParam("jobGroup") String jobGroup, @RequestParam("jobName") String jobName)throws SchedulerException {jobHandler.pauseJob(jobGroup, jobName);}/*** 繼續(xù)任務*/@RequestMapping("/continue")public void continueJob(@RequestParam("jobGroup") String jobGroup, @RequestParam("jobName") String jobName)throws SchedulerException {jobHandler.continueJob(jobGroup, jobName);}/*** 刪除任務*/@RequestMapping("/delete")public boolean deleteJob(@RequestParam("jobGroup") String jobGroup, @RequestParam("jobName") String jobName)throws SchedulerException {return jobHandler.deleteJob(jobGroup, jobName);}
}

7)測試

6.2 節(jié) 如何實現(xiàn)開啟服務自動執(zhí)行任務

@PostConstructpublic  void  init(){addMyTask();}public void addMyTask(){try {JobInfo jobInfo = new JobInfo();jobInfo.setJobGroup("group1");jobInfo.setJobName("job2");jobInfo.setCron("0/1 * * * * ?");jobInfo.setClassName("com.sh.task.MyTask");jobInfo.setTriggerName("trigger1");jobInfo.setTriggerGroup("triggerGroup1");this.addJob(jobInfo);} catch (SchedulerException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}}

6.3 節(jié) 單線程與多線程執(zhí)行任務調度的區(qū)別

6.3.1 單線程運行任務

結論:單線程運行任務不同任務之間串行,任務A運行時間會響應任務B運行間隔

6.3.2 多線程執(zhí)行任務

再創(chuàng)建一個mytask2

@DisallowConcurrentExecution
@PersistJobDataAfterExecution
@Slf4j
@Component
public class MyTask2 extends QuartzJobBean {@Overrideprotected void executeInternal(JobExecutionContext context) throws JobExecutionException {log.info("任務2執(zhí)行..." + LocalDateTime.now());}
}

?

@PostConstruct
public void init(){addMyTask();addMyTask2();
}
public void addMyTask() {try {JobInfo jobInfo = new JobInfo();jobInfo.setJobName("job1");jobInfo.setJobGroup("group1");jobInfo.setTriggerName("trigger1");jobInfo.setTriggerGroup("triggerGroup1");jobInfo.setClassName("top.psjj.task.MyTask");jobInfo.setCron("0/1 * * * * ? *");this.addJob(jobInfo);} catch (SchedulerException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}
}
public void addMyTask2() {try {JobInfo jobInfo = new JobInfo();jobInfo.setJobName("job2");jobInfo.setJobGroup("group1");jobInfo.setTriggerName("trigger2");jobInfo.setTriggerGroup("triggerGroup1");jobInfo.setClassName("top.psjj.task.MyTask2");jobInfo.setCron("0/1 * * * * ? *");this.addJob(jobInfo);} catch (SchedulerException e) {throw new RuntimeException(e);} catch (ClassNotFoundException e) {throw new RuntimeException(e);}
}

顯然任務2還是1s執(zhí)行一次,沒有收到任務1執(zhí)行時間干擾,這是任務2和任務1用的線程不同。

任務二不受任務一的影響

6.4 節(jié) 任務調度持久化的好處

如果任務調度沒有持久化,而任務又是基于動態(tài)設置,不是開機自啟的,會有一個問題,服務重啟之后設置的任務都會失效了。如果任務整合持久化之后,設置的動態(tài)任務信息就會保存到數(shù)據(jù)庫,開機自啟就會加載這些數(shù)據(jù)庫信息,就會按照原來的設置運行任務。

但是,一定要把建表配置注釋掉

#spring.quartz.jdbc.initialize-schema: always
#spring.quartz.job-store-type: jdbc

6.5 節(jié) Quartz 集群執(zhí)行與單機執(zhí)行區(qū)別

Quartz是一個開源的作業(yè)調度框架,用于在Java應用程序中調度任務。Quartz集群和非集群的區(qū)別主要體現(xiàn)在以下幾個方面:

  1. 高可用性:Quartz集群可以提供高可用性,即使其中一個節(jié)點出現(xiàn)故障,其他節(jié)點仍然可以繼續(xù)工作。而非集群模式下,如果應用程序所在的服務器出現(xiàn)故障,任務調度將會停止。

  2. 負載均衡:Quartz集群可以通過將任務分配給不同的節(jié)點來實現(xiàn)負載均衡。這意味著任務將在集群的各個節(jié)點上分布,從而提高系統(tǒng)整體的性能和吞吐量。非集群模式下,所有的任務將在單個節(jié)點上運行,可能會導致性能瓶頸。

  3. 數(shù)據(jù)共享:Quartz集群可以共享任務調度的數(shù)據(jù),包括作業(yè)和觸發(fā)器等。這意味著當一個節(jié)點添加或刪除任務時,其他節(jié)點也能夠感知到。非集群模式下,每個節(jié)點都有自己獨立的任務調度數(shù)據(jù),可能導致數(shù)據(jù)不一致。

需要注意的是,Quartz集群需要配置和管理多個節(jié)點,可能需要更多的系統(tǒng)資源和維護工作。非集群模式則相對簡單,適用于小規(guī)模的應用程序。選擇使用哪種模式應根據(jù)具體的需求和系統(tǒng)要求來決定。

?

第七章 總結

【1】簡述一下什么是任務調度?

答:任務調度就是按照特定時間規(guī)則執(zhí)行系統(tǒng)某個固定的業(yè)務邏輯。任務調度底層是使用jdk的Timer實現(xiàn)的。單體項目建議使用Spring-task任務調度技術,分布式架構建議使用quartz任務調度框架。Spring-task是單線程運行旳,Quartz是多線程運行的,且功能更為豐富,支持作業(yè)管理。

【2】說一下你都用過什么任務調度技術,他們的區(qū)別是什么?

答:Spring-task是單線程,且功能簡單。執(zhí)行任務只需開啟開關@EnableScheduling,在要執(zhí)行的任務方法上加

@Scheduled(cron = "*/1 * * * * *")注解。它的使用弊端:

  1. 任務A的執(zhí)行時間會影響任務B的執(zhí)行間隔,但是任務A和任務B是兩個任務,不應該相互影響。

  2. 沒有固定組件,持久化等功能,也就沒法形成作業(yè)系統(tǒng)

Quartz是多線程的高可用的任務調度框架,支持持久化,多線程,集群模式,且有固定組件結構Job、Trigger、scheduler。他的優(yōu)點一一說明

  1. 有固定組件,有持久化功能,這樣就能基于Quartz開發(fā)一個任務調度系統(tǒng),通過UI界面去管理任務調度。

  2. 任務進行持久化之后,重啟服務器會加載持久化的任務繼續(xù)執(zhí)行。

  3. 任務支持集群模式,如果任務調度模塊是一個集群n個節(jié)點,那么任務調度不會因為一個節(jié)點掛掉而掛掉,且任務在集群之間形成負載均衡。

http://aloenet.com.cn/news/30958.html

相關文章:

  • 購物網(wǎng)站策劃案廈門谷歌seo公司
  • 北京網(wǎng)站建設的價格中國最好的營銷策劃公司
  • 做班級的活動的網(wǎng)站企業(yè)營銷策劃方案范文
  • 招聘H5在什么網(wǎng)站做最好搜索引擎排名
  • 用手機什么軟件做網(wǎng)站百度推廣怎么操作流程
  • 帶登錄網(wǎng)站模板網(wǎng)站建設的整體流程有哪些
  • 阿里云Windows網(wǎng)站建設廣東百度推廣的代理商
  • 自助建站系統(tǒng)免授權版企業(yè)查詢網(wǎng)
  • 網(wǎng)站開發(fā)專業(yè)就業(yè)培訓學校石家莊網(wǎng)絡營銷網(wǎng)站推廣
  • 怎么免費做個人網(wǎng)站互聯(lián)網(wǎng)營銷策略有哪些
  • 網(wǎng)站怎么做?企業(yè)培訓的目的和意義
  • 一鍵清理加速北京網(wǎng)站優(yōu)化推廣方案
  • 做網(wǎng)站代理拉不到人常州網(wǎng)站推廣公司
  • 動態(tài)網(wǎng)站設計主題長春seo培訓
  • 金融跟單公司網(wǎng)站建設seo課程培訓中心
  • 網(wǎng)站推廣怎么做2017注冊域名查詢網(wǎng)站官網(wǎng)
  • 做直播的在相親網(wǎng)站交友韓國搜索引擎排名
  • 做棋牌網(wǎng)站抓到會怎么量刑廈門seo新站策劃
  • 網(wǎng)站添加鏈接網(wǎng)站申請流程
  • 櫻花代碼htmlseo外包如何
  • 大同網(wǎng)站建設熊掌號制作網(wǎng)站的公司有哪些
  • 房地產(chǎn)平面設計主要做什么貴州二級站seo整站優(yōu)化排名
  • 太原制作網(wǎng)站代理公司注冊
  • 建筑公司網(wǎng)站md0095設計風格荊門網(wǎng)絡推廣
  • 江西省贛州市地圖全圖寧波seo外包服務
  • 化妝品網(wǎng)站建設報告網(wǎng)店運營公司
  • 站長統(tǒng)計導航窗口如何搭建網(wǎng)站平臺
  • 七星網(wǎng)絡網(wǎng)站軟文范例大全500
  • 有做網(wǎng)站的公司嗎長沙seo推廣外包
  • 漯河百度做網(wǎng)站電話360推廣登錄入口