搜尋
首頁JavaJava基礎springboot+quartz 以持久化的方式實現定時任務

springboot+quartz 以持久化的方式實現定時任務

這篇文章給大家介紹springboot quartz以持久化的方式實現定時任務,詳情如下所示:

篇幅較長,耐心的人總能得到最後的答案小生第一次用quartz做定時任務,不足之處多多諒解。

首先

在springboot專案裡做定時任務是比較簡單的,最簡單的實作方式是使用**@Scheduled註解,然後在application啟動類別上使用@EnableScheduling**開啟定時任務。

範例

@SpringBootApplication
@EnableScheduling
public class Application {

 public static void main(String[] args) {
 SpringApplication.run(Application.class, args);
 }
 // cron为每秒执行一次
 @Scheduled(cron = "* * * * * ?")
 public void print(){
 System.out.println("执行定时任务");
 }

}

結果



#執行定時任務
執行定時任務
執行定時任務
執行定時任務
執行定時任務
執行定時任務

執行定時任務
執行定時任務

簡單的定時任務就可以用這種方式來做,cron表達式的結果為任務執行的間隔時間。 然而

在實際開發中,我們的任務可能有很多,需要手動操作單一/全部的任務,例如新增、開啟、停止、繼續等等操作。那麼伴隨著(千牛B類。。。)的BGM有請quartz登場。

quartz

整合

 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-quartz</artifactId>
 </dependency>

#quartz的三要素
  • ##調度器Scheduler
  • 啟動觸發器去執行任務
  • 觸發器Trigger

#用來定義Job(任務)觸發條件、觸發時間,觸發間隔,終止時間等

任務job

具體要執行的任務內容

使用

使用quartz是需要設定檔的,quartz.properties在quartz的jar套件的org.quartz套件下可以找到預設的設定檔quartz.properties

# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#
# 名字
org.quartz.scheduler.instanceName: DefaultQuartzScheduler
org.quartz.scheduler.rmi.export: false
org.quartz.scheduler.rmi.proxy: false
org.quartz.scheduler.wrapJobExecutionInUserTransaction: false
# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
# 线程总个数
org.quartz.threadPool.threadCount: 10
# 线程的优先级
org.quartz.threadPool.threadPriority: 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true

org.quartz.jobStore.misfireThreshold: 60000
# 持久化方式,默认持久化在内存中,后面我们使用db的方式
org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore

quartz任務持久化到db則需要一些官方定義的資料庫表,表的sql文件可以在quartz的jar包裡找到

坐標org.quartz.impl.jdbcjobstore,可以看到裡面有很多sql文件,有各種數據庫的,咱們用MySQL的,咱們不需要手動執行sql語句,後面咱們在啟動專案的時候會自動初始化。

建立我們自己的properties檔案

# 实例化ThreadPool时,使用的线程类为SimpleThreadPool
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
# threadCount和threadPriority将以setter的形式注入ThreadPool实例
# 并发个数
org.quartz.threadPool.threadCount=10
# 优先级
org.quartz.threadPool.threadPriority=5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread=true
org.quartz.jobStore.misfireThreshold=5000
#持久化使用的类
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
#数据库中表的前缀
org.quartz.jobStore.tablePrefix=QRTZ_
#数据源命名
org.quartz.jobStore.dataSource=qzDS
#qzDS 数据源,我们使用hikaricp,默认的是c3p0
org.quartz.dataSource.qzDS.provider=hikaricp
org.quartz.dataSource.qzDS.driver=com.mysql.cj.jdbc.Driver
org.quartz.dataSource.qzDS.URL=jdbc:mysql://localhost:3306/quartz?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
org.quartz.dataSource.qzDS.user=root
org.quartz.dataSource.qzDS.password=123456
org.quartz.dataSource.qzDS.maxConnections=10

現在我們沒有使用預設的連線池,那麼就探索一下,上原始碼!在這個套件下:org.quartz.utils,有一個PoolingConnectionProvider,顧名思義,連接池提供者部分原始碼

public interface PoolingConnectionProvider extends ConnectionProvider {

 /** The pooling provider. */
 String POOLING_PROVIDER = "provider";

 /** The c3p0 pooling provider. */
 String POOLING_PROVIDER_C3P0 = "c3p0";

 /** The Hikari pooling provider. */
 String POOLING_PROVIDER_HIKARICP = "hikaricp";

}

然後HikariCpPoolingConnectionProvider這個類別實作了PoolingConnectionProvider,自行查看。我們可以在org.quartz.impl下的StdSchedulerFactory中搜尋c3p0找到

if(poolingProvider != null && poolingProvider.equals(PoolingConnectionProvider.POOLING_PROVIDER_HIKARICP)) {
  cpClass = "org.quartz.utils.HikariCpPoolingConnectionProvider";
  }
  else {
  cpClass = "org.quartz.utils.C3p0PoolingConnectionProvider";
  }

剩下的自己多看看吧,起始源碼研究起來沒有想像中那麼難那麼乏味(我也不喜歡看源碼),但是這個原始碼看起來確實小有成就感。

回到正題頻道,設定application.yml

spring:
 datasource:
 driver-class-name: com.mysql.cj.jdbc.Driver
 password: 123456
 url: jdbc:mysql://localhost:3306/quartz?characterEncoding=UTF8&useSSL=false&serverTimezone=GMT%2B8
 username: root
 quartz:
 jdbc:
 initialize-schema: always
 job-store-type: jdbc

initialize-schema: always每次啟動項目,總是初始化資料庫表自動建立表格的關鍵地方,流程是先刪除資料庫表,再創建,如果表不存在,則拋異常,但是不會影響後面的生成表,下次再啟動專案的時候,由於表已經存在了,所以不會再拋異常了job-store-type: jdbc就是任務持久化類型,我們用jdbc

我們可能要在job裡注入spring對象,不做配置,是無法注入的。

/**
 * @author: taoym
 * @date: 2020/6/4 11:32
 * @desc: 一定要自定义JobFactory重写SpringBeanJobFactory的createJobInstance方法,否则在job中是获取不到spring容器中的bean的
 */
@Component
public class JobFactory extends SpringBeanJobFactory {

 @Autowired
 private AutowireCapableBeanFactory beanFactory;

 /**
 * 这里覆盖了super的createJobInstance方法,对其创建出来的类再进行autowire
 */
 @Override
 protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
 Object jobInstance = super.createJobInstance(bundle);
 beanFactory.autowireBean(jobInstance);
 return jobInstance;
 }
}

建立quartz的設定檔

@Configuration
public class QuartzConfig {

 @Autowired
 private JobFactory jobFactory;

 /**
 * 读取quartz.properties 文件
 * 将值初始化
 *
 * @return
 */
 @Bean
 public Properties quartzProperties() throws IOException {
 PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
 propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
 propertiesFactoryBean.afterPropertiesSet();
 return propertiesFactoryBean.getObject();
 }

 @Bean
 public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
 SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
 schedulerFactoryBean.setJobFactory(jobFactory);
 schedulerFactoryBean.setQuartzProperties(quartzProperties());
 return schedulerFactoryBean;
 }

 /**
 * 初始化监听器
 *
 * @return
 */
 @Bean
 public QuartzInitializerListener executorListener() {
 return new QuartzInitializerListener();
 }


 @Bean(name = "scheduler")
 public Scheduler scheduler() throws IOException {
 return schedulerFactoryBean().getScheduler();
 }
}

建立觸發器元件

public class TriggerComponent {

 /**
 * @author: taoym
 * @date: 2020/6/1 10:35
 * @desc: 构建cron触发器
 */
 public static Trigger cronTrigger(String cron) {
 CronTrigger cronTrigger = TriggerBuilder.newTrigger()
 .withSchedule(CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing())
 .build();
 return cronTrigger;
 }

 public static Trigger cronTrigger(String cron, JobDataMap jobDataMap) {
 CronTrigger cronTrigger = TriggerBuilder.newTrigger()
 .withSchedule(CronScheduleBuilder.cronSchedule(cron).withMisfireHandlingInstructionDoNothing())
 .usingJobData(jobDataMap)
 .build();
 return cronTrigger;
 }
}

觸發器就用這個元件來取得就行了。

建立任務

@DisallowConcurrentExecution
public class TestJob extends QuartzJobBean {
 @Override
 protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
 
 }
}

jobExecutionContext這裡面可以取得任務群組、任務名稱、觸發器群組、觸發器名稱、jobdetail等資訊。那個註解是為了讓同一個實例(jobdetail)只能單執行緒執行。可以這麼理解,job為接口,jobdetail為實現類,a是其中一個實現類,a需要花費100s執行一定的操作,而你給的定時器是沒50s就執行一次操作,a在執行到一半的時候又需要開啟一個線程來執行。使用了DisallowConcurrentExecution就相當於a沒有把操作執行完的時候,a不允許開啟執行緒再執行目前操作。不知道我的描述是否易懂!

按需建立自己的任務表,我是用定時任務做爬蟲的(小爬蟲)

CREATE TABLE `quartz_job` (
 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT &#39;编号&#39;,
 `job_name` varchar(50) DEFAULT &#39;&#39; COMMENT &#39;任务名&#39;,
 `job_group` varchar(50) DEFAULT &#39;&#39; COMMENT &#39;任务组名称&#39;,
 `job_desc` varchar(255) DEFAULT &#39;&#39; COMMENT &#39;job描述&#39;,
 `cron` varchar(50) DEFAULT &#39;&#39; COMMENT &#39;cron表达式&#39;,
 `status` tinyint(1) DEFAULT &#39;0&#39; COMMENT &#39;状态&#39;,
 `url` varchar(255) DEFAULT &#39;&#39; COMMENT &#39;请求地址&#39;,
 `param` varchar(255) DEFAULT &#39;&#39; COMMENT &#39;参数&#39;,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=31 DEFAULT CHARSET=utf8;

我們添加任務的時候不和quartz打交道,把任務放到資料庫即可。別慌,後面有用到他的地方。這個表格需要有增刪改查操作,我們會在系統中查詢任務清單選擇單一或所有任務開始執行

執行任務

@Resource
 private QuartzJobMapper quartzJobMapper;
 @Autowired
 private Scheduler scheduler;
 
 
 @Override
 public String start(Integer id) {
 
		JobDataMap jobDataMap = new JobDataMap();
 jobDataMap.put(k,v);
 
 QuartzJob quartzJob = quartzJobMapper.selectByPrimaryKey(id);
 
 JobKey jobKey = JobKey.jobKey(quartzJob.getJobName(), quartzJob.getJobGroup());
 
 jobDetail = JobBuilder.newJob(TestJob.class).withIdentity(jobKey).storeDurably().build();
 
 Trigger trigger = TriggerComponent.cronTrigger(quartzJob.getCron(), jobDataMap);
 try {
 scheduler.scheduleJob(jobDetail, trigger);
 quartzJobMapper.updateStatus(true, id);
 return "开始任务执行成功";
 } catch (SchedulerException se) {
 log.info("开始任务的时候发生了错误");
 }
 return "开始任务的时候发生了错误,请检查日志";
 }

最後我又按照此教學上的內容貼上了一遍程式碼,可以正常運作。

###

推薦教學:《PHP

以上是springboot+quartz 以持久化的方式實現定時任務的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:jb51。如有侵權,請聯絡admin@php.cn刪除

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
1 個月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
1 個月前By尊渡假赌尊渡假赌尊渡假赌
威爾R.E.P.O.有交叉遊戲嗎?
1 個月前By尊渡假赌尊渡假赌尊渡假赌

熱工具

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

DVWA

DVWA

Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中