Spring整合Quartz案例使用JDBC儲存方式
目錄
配置JobDetail和Trigger,並交給Scheduler註冊
建立資料庫表
JDBC儲存策略依賴資料庫表,資料庫表的執行指令碼可以在官網下載後解壓後的docs/dbTables資料夾中找到。
我們需要是jdbc的執行指令碼,將它在資料庫中執行,就會建立存jobDetail和Trigger等資訊的表,這些表的字首名是QRTZ_
配置資料庫連線池
jdbc.url=jdbc\:mysql\://localhost\:3306/test?useUnicode\=true&characterEncoding\=utf8&autoReconnect\=true
jdbc.username=root
jdbc.password=root
jdbc.driverClassName=com.mysql.jdbc.Driver
<context:property-placeholder location="classpath:jdbc.properties" />
<!-- 掃描包 -->
<context:component-scan base-package="cn.bing.service"></context:component-scan>
<!-- 資料來源 -->
<!-- 資料來源定義,使用c3p0 連線池 -->
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="initialPoolSize" value="2" />
<property name="minPoolSize" value="10" />
<property name="maxPoolSize" value="20" />
<property name="acquireIncrement" value="2" />
<property name="maxIdleTime" value="1800" />
</bean>
建立工作類
工作類中呼叫的業務類
會在工作類中通過獲取spring上下文,獲取bean物件呼叫
package cn.bing.service;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.stereotype.Service;
@Service("helloService")
public class HelloService {
public void hello(){
System.out.println("北京時間:["+new SimpleDateFormat("yyyyMMdd HH:mm:ss").format(new Date())+"] hello world! ..... ");
}
}
工作類
package cn.bing.job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import cn.bing.service.HelloService;
public class HelloJob extends QuartzJobBean{
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
//獲取spring容器
try {
ApplicationContext ac = (ApplicationContext) context.getScheduler().getContext().get("applicationContextKey");
HelloService service = ac.getBean("helloService", HelloService.class);
service.hello();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
配置JobDetail和Trigger,並交給Scheduler註冊
<bean id="jobDetail1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="cn.bing.job.HelloJob"></property>
<!-- 必須設定為true,如果為false,當沒有活動的觸發器與之關聯時會在排程器中會刪除該任務 -->
<property name="durability" value="true" />
<!-- 當Quartz服務被終止後,再次啟動或者叢集中的其他機器接受任務時候會嘗試恢復之前失敗的任務 -->
<property name="requestsRecovery" value="true" />
</bean>
<bean id="trigger1" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail1" />
<!-- 間隔10秒執行一次 -->
<property name="cronExpression" value="*/10 * * * * ?" />
</bean>
<!-- 將觸發器註冊到任務上 -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 資料來源 -->
<property name="dataSource" ref="dataSource"></property>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey"></property>
<property name="triggers">
<list>
<ref bean="trigger1"/>
</list>
</property>
</bean>
這裡和前面RAM儲存方式不同點,配置了dataSource屬性
測試
package cn.bing.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class QuartzTest {
public static void main(String[] args) {
ApplicationContext springContext =
new ClassPathXmlApplicationContext
(new String[]{"classpath:applicationContext.xml","classpath:quartz-config.xml"});
}
}
執行結果
北京時間:[20180802 18:00:10] hello world! .....
北京時間:[20180802 18:00:20] hello world! .....
北京時間:[20180802 18:00:30] hello world! .....
北京時間:[20180802 18:00:40] hello world! .....
北京時間:[20180802 18:00:50] hello world! .....
北京時間:[20180802 18:01:00] hello world! .....
Quartz叢集中如何工作
一個Quartz節點是一個獨立的應用,卻又管理其他節點。對於每個節點你必須分別啟動和停止。和其他伺服器叢集不同,Quartz節點並不和其他節點進行通訊,而是通過資料感知其他節點的存在。
Quartz叢集環境下配置
主要是配置quartz.properties和工作類(併發環境下的配置)
quartz.properties
org.quartz.scheduler.instanceName = TestScheduler1
org.quartz.scheduler.instanceId = AUTO
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
#觸發器超時時間(ms),超過這個時間,按照觸發器的misfire策略處理
org.quartz.jobStore.misfireThreshold = 60000
#任務的儲存策略是jdbc
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
#表字首
org.quartz.jobStore.tablePrefix = QRTZ_
org.quartz.jobStore.maxMisfiresToHandleAtATime=10
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000
org.quartz.scheduler.instanceName屬性可為任何值,用在 JDBC JobStore 中來唯一標識例項,但是所有叢集節點中必須相同。
org.quartz.scheduler.instanceId 屬性為 AUTO即可,基於主機名和時間戳來產生例項 ID。
org.quartz.jobStore.class屬性為 JobStoreTX,將任務持久化到資料中。因為叢集中節點依賴於資料庫來傳播 Scheduler 例項的狀態,你只能在使用 JDBC JobStore 時應用 Quartz 叢集。這意味著你必須使用 JobStoreTX 或是 JobStoreCMT 作為 Job 儲存;你不能在叢集中使用 RAMJobStore。
org.quartz.jobStore.isClustered 屬性為 true,你就告訴了 Scheduler 例項要它參與到一個叢集當中。這一屬性會貫穿於排程框架的始終,用於修改叢集環境中操作的預設行為。
org.quartz.jobStore.clusterCheckinInterval 屬性定義了Scheduler 例項檢入到資料庫中的頻率(單位:毫秒)。Scheduler 檢查是否其他的例項到了它們應當檢入的時候未檢入;這能指出一個失敗的 Scheduler 例項,且當前 Scheduler 會以此來接管任何執行失敗並可恢復的 Job。通過檢入操作,Scheduler 也會更新自身的狀態記錄。clusterChedkinInterval 越小,Scheduler 節點檢查失敗的 Scheduler 例項就越頻繁。預設值是 15000 (即15 秒)。
工作類
還是上面的工作類,加上註解,不允許併發執行。
package cn.bing.job;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.PersistJobDataAfterExecution;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean;
import cn.bing.service.HelloService;
@PersistJobDataAfterExecution
@DisallowConcurrentExecution//不允許併發執行
public class HelloJob extends QuartzJobBean{
@Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
//獲取spring容器
try {
ApplicationContext ac = (ApplicationContext) context.getScheduler().getContext().get("applicationContextKey");
HelloService service = ac.getBean("helloService", HelloService.class);
service.hello();
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
SchedulerFactory的xml配置
和上面沒有什麼不同,只是加上configLocation屬性,指定配置叢集的quartz.properties的檔案位置。
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 資料來源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- Quartz.properties配置檔案位置 -->
<property name="configLocation" value="classpath:quartz.properties"></property>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey"></property>
<property name="triggers">
<list>
<ref bean="trigger1"/>
</list>
</property>
</bean>
JobDetail的xml配置
和上面的配置的一樣,只是需要注意的requestsRecovery必須配置為true,這樣當一個節點沒有執行,其他節點通過資料庫感知到
那個節點沒有在指定的時刻,執行任務,就會跑一次。
<bean id="jobDetail1" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="cn.bing.job.HelloJob"></property>
<!-- 必須設定為true,如果為false,當沒有活動的觸發器與之關聯時會在排程器中會刪除該任務 -->
<property name="durability" value="true" />
<!-- 當Quartz服務被終止後,再次啟動或者叢集中的其他機器接受任務時候會嘗試恢復之前失敗的任務 -->
<property name="requestsRecovery" value="true" />
</bean>
測試叢集
在不同或者相同的機器上,執行下面的程式碼測試
我是在開啟兩個eclipse,執行下面的程式碼,停止一個後,另一個另一個將沒有跑完的任務繼續執行。
package cn.bing.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class QuartzTest {
public static void main(String[] args) {
ApplicationContext springContext =
new ClassPathXmlApplicationContext
(new String[]{"classpath:applicationContext.xml","classpath:quartz-config.xml"});
}
}
quartz水平叢集和垂直叢集的說明
Quartz 實際並不關心你是在相同的還是不同的機器上執行節點。當叢集是放置在不同的機器上時,通常稱之為水平叢集。節點是跑在同一臺機器是,稱之為垂直叢集。對於垂直叢集,存在著單點故障的問題。這對高可用性的應用來說是個壞訊息,因為一旦機器崩潰了,所有的節點也就被有效的終止了。
執行水平叢集時候,時鐘必須同步,以免出現離奇且不可預知的行為。假如時鐘沒能夠同步,Scheduler 例項將對其他節點的狀態產生混亂。有幾種簡單的方法來保證時鐘何持同步,而且也沒有理由不這麼做。最簡單的同步計算機時鐘的方式是使用某一個 Internet 時間伺服器(Internet Time Server ITS)。
沒什麼會阻止你在相同環境中使用叢集的和非叢集的 Quartz 應用。唯一要注意的是這兩個環境不要混用在相同的資料庫表。意思是非叢集環境不要使用與叢集應用相同的一套資料庫表;否則將得到希奇古怪的結果,叢集和非叢集的 Job 都會遇到問題。
假如你讓一個非叢集的 Quartz 應用與叢集節點並行著執行,設法使用 JobInitializationPlugin和 RAMJobStore。
轉載:http://sundoctor.iteye.com/blog/486055?page=2#comments
原始碼下載:https://download.csdn.net/download/ditto_zhou/10580657
相關文章
- Spring整合Quartz案例使用RAM儲存方式Springquartz
- Quartz - Spring和Quartz的整合quartzSpring
- spring-quartz整合Springquartz
- Spring Security OAuth2-基於JDBC儲存令牌SpringOAuthJDBC
- Spring Boot整合Spring Cloud Vault進行安全儲存Spring BootCloud
- jdbc使用call呼叫儲存過程報錯JDBC儲存過程
- 使用Hazelcast作為Spring資料儲存庫的開源案例ASTSpring
- spring4.x 整合quartz2.x 叢集化配置專案例項Springquartz
- Quartz - Spring整合Quartz實現叢集的定時任務quartzSpring
- Spring Boot:使用Redis儲存技術Spring BootRedis
- Spring Boot 整合阿里雲 OSS 進行檔案儲存Spring Boot阿里
- spring boot使用註解的方式整合mybaitsSpring BootAI
- 使用IDEA的SpringBoot整合JDBCIdeaSpring BootJDBC
- 使用 .NET 整合 MinIO 實現高效物件儲存物件
- 如何實現Spring Boot和Quartz整合? - Nguyen Phuc HaiSpring BootquartzAI
- 使用Spring Boot實現資料庫整合配置案例Spring Boot資料庫
- 使用Spring Data建立只讀儲存庫 | BaeldungSpring
- JavaWeb——JDBC八股文、JSBC使用儲存過程、儲存函式、處理CLOB/BLOB型別JavaWebJDBCJS儲存過程儲存函式型別
- Spring Session JDBC的使用 - javadevjournalSpringSessionJDBCJavadev
- Python資料儲存方式有幾種?如何使用?Python
- 【Springboot】快速整合QuartzSpring Bootquartz
- SpringBoot 整合 Quartz + MySQLSpring BootquartzMySql
- Spring整合Mybatis方式二 - SqlSessionTemplateSpringMyBatisSQLSession
- block底層儲存方式BloC
- Spring Boot 整合 Spring Security 入門案例教程Spring Boot
- VSAN儲存結構解析+儲存資料恢復案例資料恢復
- Spring Boot 揭祕與實戰(二) 資料儲存篇 – MyBatis整合Spring BootMyBatis
- 摩杜雲:物件儲存可以透過哪些方式使用?物件
- 日期的正確儲存方式
- 【Spring】jdbcSpringJDBC
- Django整合騰訊COS物件儲存Django物件
- 使用Spring Data JDBC實現DDD聚合SpringJDBC
- JavaScript本地儲存的方式有哪些JavaScript
- Java常見的本地儲存方式Java
- Go操作騰訊雲COS物件儲存的簡單使用案例Go物件
- Quartz.NET整合UI版quartzUI
- Spring Cloud Alibaba基礎教程:Sentinel使用Nacos儲存規則SpringCloud
- Spring Cloud Alibaba基礎教程:Sentinel使用Apollo儲存規則SpringCloud