1. 程式人生 > >Spring+Quartz框架實現定時任務(集群,分布式)

Spring+Quartz框架實現定時任務(集群,分布式)

log cor alt 放置 這一 表達 mod 建數據庫 strac

1、定時任務的必要性:

定時任務在應用中的重要性不言而喻,大多是應用,特別是金融應用更是離不開定時任務,能用定時任務來處理異常訂單,完成跑批,定時活動(雙11)等。
在初期應用的訪問量並不是那麽大,一臺服務器完全滿足使用,但是隨著用戶量、業務量的逐日增加,應用中會有很多定時任務需要執行,一臺服務器已經不能滿足使用,
因此需要把應用給部署到集群中,前端通過nginx代理實現訪問。

2、集群使用定時任務的問題:
目前大部分在集群中處理定時任務的方式不是正真的分布式處理方式,而是一種偽分布式,這種方式存在一個明顯的缺陷就是當集群中機器宕機,
那麽整個定時任務就會掛掉或者不能一次性跑完,會對業務產生嚴重的影響。

而且在集群環境中,同樣的定時任務,在集群中的每臺服務器都會執行,這樣定時任務就會重復執行,不但會增加服務器的負擔,還會因為定時任務重復執行造成額外的不可預期的錯誤。
解決方案是:
根據集群的數量,把定時任務中的任務平均分到集群中的每臺機器上(這裏的平均分是指以前多個定時任務本來是在一臺機器上運行,先在人為的把這些任務分成幾部分,讓所有的機器分別去執行這些任務)
這就是采用了分布式定時任務來進行處理。
另外一種解決方式:
使用Quartz框架,在集群環境下,通過數據庫鎖機制來實現定時任務的執行,下面會介紹。


3、Quartz介紹:

Quartz是一個開放源碼項目,專註於任務調度器,提供了極為廣泛的特性如持久化任務,集群和分布式任務等。
Quartz核心是調度器,還采用多線程管理。quartz框架是原生就支持分布式定時任務的。

1.持久化任務(把調度信息存儲到數據):當應用程序停止運行時,所有調度信息不被丟失,當你重新啟動時,調度信息還存在,這就是持久化任務。

2.集群和分布式處理:當在集群環境下,當有配置Quartz的多個客戶端時(節點),
采用Quartz的集群和分布式處理時,我們要了解幾點好處
1) 一個節點無法完成的任務,會被集群中擁有相同的任務的節點取代執行。
2) Quartz調度是通過觸發器的類別來識別不同的任務,在不同的節點定義相同的觸發器的類別,這樣在集群下能穩定的運行,一個節點無法完成的任務,會被集群中擁有相同的任務的節點取代執行。
3)分布式 體現在 當相同的任務定時在一個時間點,在那個時間點,不會被兩個節點同時執行。

4、Quartz 在集群如何工作:

技術分享圖片

一個 Quartz 集群中的每個節點是一個獨立的 Quartz 應用,你必須對每個節點分別啟動或停止。
大多數應用服務器的集群,獨立的 Quartz 節點並不與另一其的節點或是管理節點通信,彼此相互獨立。
Quartz 應用是通過數據庫表來感知到另一應用的,調度信息存儲在數據庫中,當集群定時任務操作數據庫(讀取任務信息,更新任務信息)
數據庫就會被加鎖,防止其他相同的任務也讀取到該任務,避免任務的重復執行。

5、環境搭建-創建Quartz數據庫表

因為Quartz 集群依賴於數據庫,所以必須首先創建Quartz數據庫表。
Quartz 包括了所有被支持的數據庫平臺的 SQL 腳本。在 <quartz_home>/docs/dbTables 目錄下找到那些 SQL 腳本,這裏的 <quartz_home> 是解壓 Quartz 分發包後的目錄。
Quartz 2.2.3版本,總共11張表,不同版本,表個數可能不同。數據庫為mysql,用tables_mysql_innodb.sql創建數據庫表,數據庫不同選擇的建表sql也不同,根據自己選擇。

6、環境搭建-配置 Quartz 使用集群

1.配置節點的 quartz.properties 文件

# Configure Main Scheduler Properties
# Needed to manage cluster instances
org.quartz.scheduler.instanceName = TestScheduler1
org.quartz.scheduler.instanceId = AUTO

# Configure ThreadPool
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true


# Configure JobStore
# Using Spring datasource in quartzJobsConfig.xml
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
org.quartz.jobStore.misfireThreshold = 60000
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 秒)。


7、配置applicationContext-quartz.xml文件,在這裏配置任務,數據庫連接等

[html] view plain copy
  1. <span style="font-size:14px;"><beans xmlns="http://www.springframework.org/schema/beans"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" </span>
[html] view plain copy
  1. <span style="font-size:14px;"><span style="white-space:pre"> </span>xmlns:context="http://www.springframework.org/schema/context"
  2. xsi:schemaLocation="http://www.springframework.org/schema/beans
  3. http://www.springframework.org/schema/beans/spring-beans-4.0.xsd </span>
[html] view plain copy
  1. <span style="font-size:14px;"><span style="white-space:pre"> </span>http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
  2. <!-- 配置掃描的包 -->
  3. <context:component-scan base-package="com.clusterquartz.job" />
  4. <!-- JNDI連接數據庫 -->
  5. <bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
  6. <!-- tomcat -->
  7. <!--<property name="jndiName" value="java:comp/env/jndi/mysql/quartz"/> -->
  8. <!-- jboss -->
  9. <property name="jndiName" value="jdbc/quartz" />
  10. </bean>
  11. <!-- 分布式事務配置 start -->
  12. <!-- 配置線程池 -->
  13. <bean name="executor"
  14. class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
  15. <property name="corePoolSize" value="15" />
  16. <property name="maxPoolSize" value="25" />
  17. <property name="queueCapacity" value="100" />
  18. </bean>
  19. <!-- 配置事務管理器 -->
  20. <bean name="transactionManager"
  21. class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  22. <property name="dataSource" ref="dataSource" />
  23. </bean>
  24. <!-- 配置調度任務 -->
  25. <bean name="quartzScheduler"
  26. class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  27. <property name="configLocation" value="classpath:quartz.properties" />
  28. <property name="dataSource" ref="dataSource" />
  29. <property name="transactionManager" ref="transactionManager" />
  30. <!-- 任務唯一的名稱,將會持久化到數據庫 -->
  31. <property name="schedulerName" value="baseScheduler" />
  32. <!-- 每臺集群機器部署應用的時候會更新觸發器 -->
  33. <property name="overwriteExistingJobs" value="true" />
  34. <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
  35. <property name="jobFactory">
  36. <bean
  37. class="com.clusterquartz.autowired.AutowiringSpringBeanJobFactory" />
  38. </property>
  39. <property name="triggers">
  40. <list>
  41. <ref bean="printCurrentTimeScheduler" />
  42. </list>
  43. </property>
  44. <property name="jobDetails">
  45. <list>
  46. <ref bean="printCurrentTimeJobs" />
  47. </list>
  48. </property>
  49. <property name="taskExecutor" ref="executor" />
  50. </bean>
  51. <!-- 配置Job詳情,job實現業務邏輯 -->
  52. <bean name="printCurrentTimeJobs"
  53. class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
  54. <property name="jobClass"
  55. value="com.clusterquartz.job.PrintCurrentTimeJobs" />
  56. <property name="durability" value="true" />
  57. <property name="requestsRecovery" value="true" />
  58. </bean>
  59. <!-- 配置觸發時間 -->
  60. <bean name="printCurrentTimeScheduler"
  61. class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
  62. <property name="jobDetail" ref="printCurrentTimeJobs" />
  63. <property name="cronExpression">
  64. <value>0/2 * * * * ?</value>
  65. </property>
  66. </bean>
  67. <!-- 分布式事務配置 end -->
  68. <!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任務類可以不實現Job接口,通過targetMethod指定調用方法 -->
  69. <!-- 定義目標bean和bean中的方法 -->
  70. <bean id="SpringQtzJob" class="com.clusterquartz.job.SpringQtz" />
  71. <bean id="SpringQtzJobMethod"
  72. class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
  73. <property name="targetObject">
  74. <ref bean="SpringQtzJob" />
  75. </property>
  76. <property name="targetMethod"> <!-- 要執行的方法名稱 -->
  77. <value>execute</value>
  78. </property>
  79. </bean>
  80. <!-- 調度觸發器 -->
  81. <bean name="printCurrentTimeScheduler"
  82. class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
  83. <property name="jobDetail" ref="SpringQtzJobMethod" />
  84. <property name="cronExpression">
  85. <value>0/10 * * * * ?</value>
  86. </property>
  87. </bean>
  88. </beans></span>



applicationContextSchedulerContextKey:
是org.springframework.scheduling.quartz.SchedulerFactoryBean這個類中把spring上下文以key/value的方式存放在了SchedulerContext中了,
可以用applicationContextSchedulerContextKey所定義的key得到對應spring 的ApplicationContext;
會在後面的類裏用到

configLocation:用於指明quartz的配置文件的位置


requestsRecovery:
屬性必須設置為 true,當Quartz服務被中止後,再次啟動或集群中其他機器接手任務時會嘗試恢復執行之前未完成的所有任務。




8、介紹相關的類:

1、

[html] view plain copy
  1. <property name="jobFactory">
  2. <bean
  3. class="com.clusterquartz.autowired.AutowiringSpringBeanJobFactory" />
  4. </property>


這個類的作用:

[java] view plain copy
  1. <span style="font-size:14px;">/**
  2. * @author
  3. * @description 使我們的任務類支持Spring的自動註入
  4. */
  5. public class AutowiringSpringBeanJobFactory extends SpringBeanJobFactory
  6. implements ApplicationContextAware {
  7. private transient AutowireCapableBeanFactory beanFactory;
  8. public void setApplicationContext(ApplicationContext applicationContext)
  9. throws BeansException {
  10. beanFactory = applicationContext.getAutowireCapableBeanFactory();
  11. }
  12. @Override
  13. protected Object createJobInstance(TriggerFiredBundle bundle)
  14. throws Exception {
  15. Object job = super.createJobInstance(bundle);
  16. beanFactory.autowireBean(job);
  17. return job;
  18. }
  19. }</span>



調用我們任務類的實現:
/**
* @author
* @description 當前任務是每隔一定時間打印當前的時間
*/
public class PrintCurrentTimeJobs extends QuartzJobBean {
private static final Log LOG_RECORD = LogFactory
.getLog(PrintCurrentTimeJobs.class);
/*
* 這裏就是因為有上文中的AutowiringSpringBeanJobFactory才可以使用像@Autowired的註解,當然還可以使用Spring的其他註解
* 否則只能在配置文件中設置這屬性的值,另一種方式下面說到
*/
@Autowired
private ClusterQuartz clusterQuartz;


protected void executeInternal(JobExecutionContext jobExecutionContext)
throws JobExecutionException {
LOG_RECORD.info("begin to execute task,"
+ DateUtil.dateFmtToString(new Date()));
//我們真正要執行的任務
clusterQuartz.printUserInfo();


LOG_RECORD.info("end to execute task,"
+ DateUtil.dateFmtToString(new Date()));
}
}


我們定時任務的具體邏輯實現:(我們很熟悉的Spring,註解開發)
@Service("ClusterQuartz")
public class ClusterQuartz {
private static final Logger logger = LoggerFactory
.getLogger(ClusterQuartz.class);


/*在這裏可以使用spring的註解,引入各種服務之類的*/

/*@Resource(name = "miService")
private MiService miService;


@Autowired
private PushServiceI pushRecordService;*/

public void printUserInfo() {
System.out.println("定時任務的實現邏輯代碼");


}
}




2、如果不配置上面1的那個property,我們的定時任務這樣實現:

[java] view plain copy
  1. <span style="white-space:pre"> </span><span style="font-size:14px;">//執行定時任務的類
  2. @PersistJobDataAfterExecution
  3. @DisallowConcurrentExecution
  4. // 不允許並發執行
  5. public class MyQuartzJobBean1 extends QuartzJobBean {
  6. private static final Logger logger = LoggerFactory
  7. .getLogger(MyQuartzJobBean1.class);
  8. @Override
  9. protected void executeInternal(JobExecutionContext jobexecutioncontext)
  10. throws JobExecutionException {
  11. SimpleService simpleService = getApplicationContext(jobexecutioncontext)
  12. .getBean("simpleService", SimpleService.class);
  13. //我們定時任務的方法
  14. simpleService.testMethod1();
  15. }
  16. private ApplicationContext getApplicationContext(
  17. final JobExecutionContext jobexecutioncontext) {
  18. try {
  19. //在這裏用applicationContextSchedulerContextKey所定義的key得到對應spring 的ApplicationContext;
  20. return (ApplicationContext) jobexecutioncontext.getScheduler()
  21. .getContext().get("applicationContextKey");
  22. } catch (SchedulerException e) {
  23. logger.error(
  24. "jobexecutioncontext.getScheduler().getContext() error!", e);
  25. throw new RuntimeException(e);
  26. }
  27. }
  28. }
  29. 而定時任務的具體邏輯業務,還是和上面的一樣。
  30. @Service("simpleService")
  31. public class SimpleService {
  32. private static final Logger logger = LoggerFactory.getLogger(SimpleService.class);
  33. public void testMethod1(){
  34. //這裏執行定時調度業務
  35. logger.info("testMethod1.......1");
  36. System.out.println("2--testMethod1......."+System.currentTimeMillis()/1000);
  37. }
  38. public void testMethod2(){
  39. logger.info("testMethod2.......2");
  40. }
  41. }</span>



9、運行測試Quartz集群定時任務:


public class MainTest {
public static void main(String[] args) {
ApplicationContext springContext = new ClassPathXmlApplicationContext(
new String[] { "classpath:applicationContext.xml",
"classpath:applicationContext-quartz.xml" });
}


}


10、在Spring中使用Quartz有兩種方式實現:


第一種是任務類繼承QuartzJobBean,第二種則是在配置文件裏定義任務類和要執行的方法,類和方法仍然是普通類。
很顯然,第二種方式遠比第一種方式來的靈活。我們發現上面采用的就是第一種方法,下面說下第二種方法。


1、配置XML如下:

<!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任務類可以不實現Job接口,通過targetMethod指定調用方法 -->
<!-- 定義目標bean和bean中的方法 -->
<bean id="SpringQtzJob" class="com.clusterquartz.job.SpringQtz" />
<bean id="SpringQtzJobMethod"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="SpringQtzJob" />
</property>
<property name="targetMethod"> <!-- 要執行的方法名稱 -->
<value>execute</value>
</property>
</bean>
<!-- 調度觸發器 -->
<bean name="printCurrentTimeScheduler"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="SpringQtzJobMethod" />
<property name="cronExpression">
<value>0/10 * * * * ?</value>
</property>
</bean>


2、任務類:(普通的Java類)

public class SpringQtz {
private static int counter = 0;


protected void execute() {
long ms = System.currentTimeMillis();
System.out.println("\t\t" + new Date(ms));
System.out.println("(" + counter++ + ")");
}
}


11、Quartz版本問題:


spring3.1以下的版本必須使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然會出錯。
不匹配異常:
Caused by: org.springframework.beans.factory.CannotLoadBeanClassException: Error loading class [org.springframework.scheduling.quartz.CronTriggerBean] for bean with name ‘mytrigger‘ defined in class path resource [applicationContext.xml]: problem with class file or dependent class; nested exception is java.lang.IncompatibleClassChangeError: class org.springframework.scheduling.quartz.CronTriggerBean has interface org.quartz.CronTrigger as super class
異常原因:
spring3.0.5中org.springframework.scheduling.quartz.CronTriggerBean繼承了org.quartz.CronTrigger(public class CronTriggerBeanextends CronTrigger),
而在quartz2.1.3中org.quartz.CronTrigger是個接口(publicabstract interface CronTrigger extends Trigger),
而在quartz1.8.5及1.8.4中org.quartz.CronTrigger是個類(publicclass CronTrigger extends Trigger),
從而造成無法在applicationContext中配置觸發器。這是spring3.1以下版本和quartz2版本不兼容的一個bug。




12、關於cronExpression表達式,這裏提一下:
字段 允許值 允許的特殊字符
秒 0-59 , - * /
分 0-59 , - * /
小時 0-23 , - * /
日期 1-31 , - * ? / L W C
月份 1-12 或者 JAN-DEC , - * /
星期 1-7 或者 SUN-SAT , - * ? / L C #
年(可選) 留空, 1970-2099 , - * /
表達式意義
"0 0 12 * * ?" 每天中午12點觸發
"0 15 10 ? * *" 每天上午10:15觸發
"0 15 10 * * ?" 每天上午10:15觸發
"0 15 10 * * ? *" 每天上午10:15觸發
"0 15 10 * * ? 2005" 2005年的每天上午10:15觸發
"0 * 14 * * ?" 在每天下午2點到下午2:59期間的每1分鐘觸發
"0 0/5 14 * * ?" 在每天下午2點到下午2:55期間的每5分鐘觸發
"0 0/5 14,18 * * ?" 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發
"0 0-5 14 * * ?" 在每天下午2點到下午2:05期間的每1分鐘觸發
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44觸發
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15觸發
"0 15 10 15 * ?" 每月15日上午10:15觸發
"0 15 10 L * ?" 每月最後一日的上午10:15觸發
"0 15 10 ? * 6L" 每月的最後一個星期五上午10:15觸發
"0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最後一個星期五上午10:15觸發
"0 15 10 ? * 6#3" 每月的第三個星期五上午10:15觸發
每天早上6點
0 6 * * *
每兩個小時
0 */2 * * *
晚上11點到早上8點之間每兩個小時,早上八點
0 23-7/2,8 * * *
每個月的4號和每個禮拜的禮拜一到禮拜三的早上11點
0 11 4 * 1-3
1月1日早上4點
0 4 1 1 *




13、一般applicationContext-quartz.xml的框架配置:


<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 任務調度配置 -->
<bean name="quartzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<!-- 配置數據庫 -->
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
<property name="configLocation" value="classpath:quartz.properties" />
<property name="triggers">
<!-- 類似的可以在這裏添加定時任務觸發器 -->
<list>
<ref bean="trigger1" />
<ref bean="trigger2" />
</list>
</property>
</bean>


<!-- 任務具體工廠 -->
<bean id="jobDetail1"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<!-- 具體實現類,當然這裏我們的class繼承 QuartzJobBean了 -->
<property name="jobClass">
<value>com.sundoctor.quartz.cluster.example.MyQuartzJobBean1</value>
</property>
<property name="durability" value="true" />
<property name="requestsRecovery" value="true" />
</bean>
<!-- 配置觸發器,包含執行時間,具體任務等 -->
<bean id="trigger1"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobDetail1" />
<property name="cronExpression" value="0/10 * * * * ?" />
</bean>
</beans>


14、Quartz運行解釋:


Quartz 實際並不關心你是在相同的還是不同的機器上運行節點。
當集群是放置在不同的機器上時,通常稱之為水平集群。節點是跑在同一臺機器是,稱之為垂直集群。
對於垂直集群,存在著單點故障的問題。這對高可用性的應用來說是個壞消息,因為一旦機器崩潰了,所有的節點也就被有效的終止了。


當你運行水平集群時,時鐘應當要同步,以免出現離奇且不可預知的行為。
假如時鐘沒能夠同步,Scheduler 實例將對其他節點的狀態產生混亂。
有幾種簡單的方法來保證時鐘何持同步,而且也沒有理由不這麽做。最簡單的同步計算機時鐘的方式是使用某一個 Internet 時間服務器(Internet Time Server ITS)。


沒什麽會阻止你在相同環境中使用集群的和非集群的 Quartz 應用。
唯一要註意的是這兩個環境不要混用在相同的數據庫表。
意思是非集群環境不要使用與集群應用相同的一套數據庫表;否則將得到希奇古怪的結果,集群和非集群的 Job 都會遇到問題。

假如你讓一個非集群的 Quartz 應用與集群節點並行著運行,設法使用 JobInitializationPlugin和 RAMJobStore。


15、配置數據庫連接,


1、通用的
<!-- 數據源定義,使用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>


2、JNDI連接數據庫


<!-- JNDI連接數據庫 -->
<bean name="dataSource" class="org.springframework.jndi.JndiObjectFactoryBean">
<!-- tomcat -->
<!--<property name="jndiName" value="java:comp/env/jndi/mysql/quartz"/> -->


<!-- jboss -->
<property name="jndiName" value="jdbc/quartz" />
</bean>

3、Druid連接池(公司用)

<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="${jdbc_url}" />
<property name="username" value="${jdbc_username}" />
<property name="password" value="${jdbc_password}" />
<property name="initialSize" value="0" />
<property name="maxActive" value="20" />
<property name="maxIdle" value="50" />
<property name="minIdle" value="0" />
<property name="maxWait" value="60000" />
<property name="validationQuery" value="${validationQuery}" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="testWhileIdle" value="true" />
<!-- 配置間隔多久才進行一次檢測,檢測需要關閉的空閑連接,單位是毫秒 -->
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<!-- 配置一個連接在池中最小生存的時間,單位是毫秒 -->
<property name="minEvictableIdleTimeMillis" value="300000" />
<!-- 打開removeAbandoned功能 -->
<property name="removeAbandoned" value="true" />
<!-- 1800秒,也就是30分鐘 -->
<property name="removeAbandonedTimeout" value="1800" />
<!-- 關閉abanded連接時輸出錯誤日誌 -->
<property name="logAbandoned" value="true" />
<!-- 打開PSCache,並且指定每個連接上PSCache的大小 如果用Oracle,則把poolPreparedStatements配置為true,mysql可以配置為false。 -->
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize"
value="20" />
<!-- 解密密碼必須要配置的項 -->
<property name="filters" value="wall,stat,config" />
<property name="connectionProperties"
value="config.decrypt=true;config.decrypt.key=${jdbc_publickey}" />
</bean>

在我的資源裏上傳了上面實例的代碼,有需要的支持下,有不當之處,望各位猿友之處,萬分感謝。

相信您一定對定時任務又有了深刻的認識

每天努力一點,每天都在進步。

Spring+Quartz框架實現定時任務(集群,分布式)