一、背景
SSM項目中要用到定時器,初期使用Timer,后來用spring 的schedule,都比較簡單,所以功能比較單一而且他們不能動態的配置時間。后來就研究quartz,准備整合到項目中。Quartz 是一個完全由 Java 編寫的開源作業調度框架,為在 Java 應用程序中進行作業調度提供了簡單卻強大的機制。
二、quartz的官網下載壓縮包
最好下載穩定版,我這里下載的是2.3.0,quartz下載地址。
三、建立數據庫,導入sql腳本
sql腳本的位置:quartz-2.3.0-distribution\quartz-2.3.0-SNAPSHOT\src\org\quartz\impl\jdbcjobstore\tables_mysql_innodb.sql(我項目中使用的mysql),這里要注意,不同類型的數據庫要用不同的數據庫腳本;
四、Maven中導入依賴
這里quartz的版本必須與數據庫腳本的版本一致不然會報錯。因為quartz的每個版本數據庫改動挺大的,假如這里配置的2.3.0,而你用2.1.7的sql腳本,肯定會出錯。所以要一一匹配。
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.3.0</version> </dependency>
五、配置文件
quartz的持久化有兩種,一種是RAM,一種是JDBC。
RAMJobStore是使用最簡單的JobStore,它也是性能最高的(在CPU時間方面)。RAMJobStore以其明顯的方式獲取其名稱:它將其所有數據保存在RAM中。這就是為什么它是閃電般快的,也是為什么這么簡單的配置。缺點是當您的應用程序結束(或崩潰)時,所有調度信息都將丟失 - 這意味着RAMJobStore無法履行作業和triggers上的“非易失性”設置。對於某些應用程序,這是可以接受的 - 甚至是所需的行為,但對於其他應用程序,這可能是災難性的。
JDBCJobStore也被恰當地命名 - 它通過JDBC將其所有數據保存在數據庫中。因此,配置比RAMJobStore要復雜一點,而且也不是那么快。但是,性能下降並不是很糟糕,特別是如果您在主鍵上構建具有索引的數據庫表。在相當現代的一套具有體面的LAN(在調度程序和數據庫之間)的機器上,檢索和更新觸發triggers的時間通常將小於10毫秒。
本次整合采用的是JDBCStore。如果你采用RAMStore,你只需要將org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX注釋掉,把Configure Datasources標簽中的內容注釋掉。
# Default Properties file for use by StdSchedulerFactory # to create a Quartz Scheduler Instance, if a different # properties file is not explicitly specified. # #============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceName: quartzScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.scheduler.rmi.export: false org.quartz.scheduler.rmi.proxy: false org.quartz.scheduler.wrapJobExecutionInUserTransaction: false #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount: 2 org.quartz.threadPool.threadPriority: 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true org.quartz.jobStore.misfireThreshold: 60000 #============================================================================ # Configure JobStore #============================================================================ #default config #org.quartz.jobStore.class: org.quartz.simpl.RAMJobStore #持久化配置 org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass:org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.useProperties:true #============================================================================ #havent cluster spring #============================================================================ org.quartz.jobStore.isClustered = false #數據庫表前綴 org.quartz.jobStore.tablePrefix:qrtz_ #============================================================================ # Configure Datasources,如果在spring的配置文件中,指定dataSource,那么就是用的spring中已經配置好的數據源,即被覆蓋。如果沒有指定dataSource,則使用的是此處配置的數據庫參數 #============================================================================ org.quartz.jobStore.dataSource:qzDS org.quartz.dataSource.qzDS.driver:com.mysql.jdbc.Driver org.quartz.dataSource.qzDS.URL:jdbc:mysql://localhost:3306/magicmedecg org.quartz.dataSource.qzDS.user:root org.quartz.dataSource.qzDS.password:root
六、spring與quartz的整合配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:websocket="http://www.springframework.org/schema/websocket" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd"> <!-- quartz --> <bean id="scheduleReportFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!--這里使用的是spring中已經配置好的數據源;當然如果不配置則使用quartz.properties中的數據庫配置。-->
<property name="dataSource"> <ref bean="dataSource"/> </property> <property name="startupDelay" value="100"/> <property name="applicationContextSchedulerContextKey" value="applicationContextKey"/> <property name="configLocation" value="classpath:quartz.properties"/> </bean> </beans>
七、定義Job類
這里的@Setter是生成類的屬性的setter方法,這個注解不是quartz的,而是lombok的。@sertter = 屬性的setter方法。
@Setter
public class RemindUserJob implements Job {
private String appuserId;
private String orderSn;
private static int count = 0;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
System.out.println("我執行了,時間是" + System.currentTimeMillis() + ",count = " + count + ",appuserId = " + appuserId + ",orderSn=" + orderSn);
count++;
}
}
八、創建任務
@RequestMapping("test04") @ResponseBody public void test04() throws Exception { // 創建scheduler Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler(); // 創建JobDetail JobDetail jobDetail = newJob(RemindUserJob.class) .withIdentity("job1", "group1") .usingJobData("appuserId", "asdfghjkl") .usingJobData("orderSn", "0as8fg") .build(); // 指定時間觸發,每隔2s執行一次,重復20次 Trigger trigger2 = newTrigger() .withIdentity("trigger2", "group1") .startAt(new Date()) .withSchedule(simpleSchedule() .withIntervalInSeconds(2) .withRepeatCount(20)) .build(); scheduler.scheduleJob(jobDetail,trigger2); scheduler.start(); }
九、運行效果
[2019-03-25 15:11:08,149] [org.quartz.impl.StdSchedulerFactory] : Quartz scheduler 'quartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties' [2019-03-25 15:11:08,150] [org.quartz.impl.StdSchedulerFactory] : Quartz scheduler version: 2.3.0 [2019-03-25 15:11:08,255] [com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource] : Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 30, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 0, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 1hge15ka11duunroghgkbm|aa25642, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 1hge15ka11duunroghgkbm|aa25642, idleConnectionTestPeriod -> 0, initialPoolSize -> 3, jdbcUrl -> jdbc:mysql://localhost:3306/magicmedecg, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 0, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 10, maxStatements -> 0, maxStatementsPerConnection -> 120, minPoolSize -> 1, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ] [2019-03-25 15:11:08,525] [org.quartz.impl.jdbcjobstore.JobStoreTX] : Freed 0 triggers from 'acquired' / 'blocked' state. [2019-03-25 15:11:08,530] [org.quartz.impl.jdbcjobstore.JobStoreTX] : Recovering 0 jobs that were in-progress at the time of the last shut-down. [2019-03-25 15:11:08,530] [org.quartz.impl.jdbcjobstore.JobStoreTX] : Recovery complete. [2019-03-25 15:11:08,532] [org.quartz.impl.jdbcjobstore.JobStoreTX] : Removed 0 'complete' triggers. [2019-03-25 15:11:08,534] [org.quartz.impl.jdbcjobstore.JobStoreTX] : Removed 0 stale fired job entries. [2019-03-25 15:11:08,535] [org.quartz.core.QuartzScheduler] : Scheduler quartzScheduler_$_NON_CLUSTERED started. 我執行了,時間是1553497868902,count = 0,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497870183,count = 1,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497872178,count = 2,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497874183,count = 3,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497876179,count = 4,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497878177,count = 5,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497880178,count = 6,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497882180,count = 7,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497884183,count = 8,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497886184,count = 9,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497888176,count = 10,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497890175,count = 11,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497892177,count = 12,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497894178,count = 13,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497896176,count = 14,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497898190,count = 15,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497900381,count = 16,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497902176,count = 17,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497904205,count = 18,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497906175,count = 19,appuserId = asdfghjkl,orderSn=0as8fg 我執行了,時間是1553497908177,count = 20,appuserId = asdfghjkl,orderSn=0as8fg
注:整合過程中可能遇到的異常:spring整合quartz異常:org.quartz.JobPersistenceException: Couldn't clean volatile data: Unknown column 'IS_VOLATILE' in 'where clause'