最近需要用到Quartz進行定時任務功能,通過近期研究發現,spring已經很好的集成Quartz,它主要是屏蔽了Quartz底層一些配置,使開發人員可以幾乎不受到任何限制就能夠利用Quartz進行定時任務的工作,這里主要是通過實例的方式對利用Spring進行Quartz定時開發的兩種方式進行講解。
1、功能需求
需要每個30秒對系統指定目錄進行掃描,把符合條件的文件進行解析入庫工作,這里只提取出有關頂事任務的內容
2、研究一下Spring+Quartz結合方式,大體有兩種方式可以達到定時任務功能
2.1 借助于Spring的org.springframework.scheduling.quartz.JobDetailBean的類功能,繼承Spring封裝Quartz的org.springframework.scheduling.quartz.QuartzJobBean類,要實現executeInternal方法,并把其中涉及到需要定時任務處理的功能放入其中
Spring配置如下:
1
2
<bean id="saveProjectJob"
3
class="org.springframework.scheduling.quartz.JobDetailBean">
4
<property name="jobClass">
5
<value>
6
com.gresoft.components.fileupload.service.ParseFileQuartz
7
</value>
8
</property>
9
<property name="jobDataAsMap">
10
<map>
11
<entry key="readXmlService">
12
<ref bean="readXmlService" />
13
</entry>
14
</map>
15
</property>
16
</bean>
17
<bean id="saveCron"
18
class="org.springframework.scheduling.quartz.CronTriggerBean">
19
<property name="jobDetail">
20
<ref local="saveProjectJob" />
21
</property>
22
<property name="cronExpression">
23
<value>0/30 * * * * ?</value>
24
</property>
25
</bean>
26
<bean id="scheduler"
27
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
28
<property name="triggers">
29
<ref local="saveCron" />
30
</property>
31
</bean>
注意上述紅色字體<map>結點,這里主要是為了在定時任務需要使用到Bean,通過Spring給注入進來,如果不寫明,就會報
java.lang.NullPointerException錯誤,主要是因為沒有注入Bean
方法代碼如下:
1
package com.gresoft.components.fileupload.service;
2
3
import org.quartz.JobExecutionContext;
4
import org.quartz.JobExecutionException;
5
import org.springframework.scheduling.quartz.QuartzJobBean;
6
7
public class ParseFileQuartz extends QuartzJobBean
{
8
private readXmlService readXmlService;
9
10
@Override
11
protected void executeInternal(JobExecutionContext jobexecutioncontext)
12
throws JobExecutionException
{
13
// TODO Auto-generated method stub
14
// System.out.println(genderManager.get(1).getGenderName());
15
readXmlService.refreshFileList("D:/tomcat/webapps/sanitation/upload");
16
}
17
18
public void setReadXmlService(readXmlService readXmlService)
{
19
this.readXmlService = readXmlService;
20
}
21
}
22
2.2 借助于Spring 的org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean類,使用此方法使開發人員對Quartz完全透明,需要實現定時任務的方法只是一個普通方法
Spring配置文件如下:
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN 2.0//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
3
<beans>
4
5
<bean id="saveProjectJob"
6
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
7
<property name="targetObject">
8
<ref local="parseQuartz" />
9
10
</property>
11
<property name="targetMethod">
12
<value>execute</value>
13
</property>
14
15
16
</bean>
17
<bean id="parseQuartz" class="com.gresoft.components.fileupload.service.ParseFileQuartzOther">
18
<property name="readXmlService" ref="readXmlService" />
19
</bean>
20
<bean id="saveCron"
21
class="org.springframework.scheduling.quartz.CronTriggerBean">
22
<property name="jobDetail">
23
<ref local="saveProjectJob" />
24
</property>
25
<property name="cronExpression">
26
<value>0/30 * * * * ?</value>
27
</property>
28
</bean>
29
<bean id="scheduler"
30
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
31
<property name="triggers">
32
<ref local="saveCron" />
33
</property>
34
</bean>
35
業務代碼如下:
1
package com.gresoft.components.fileupload.service;
2
3
public class ParseFileQuartzOther
{
4
private readXmlService readXmlService;
5
6
7
public void execute()
{
8
// TODO Auto-generated method stub
9
// System.out.println(genderManager.get(1).getGenderName());
10
readXmlService.refreshFileList("D:/tomcat/webapps/sanitation/upload");
11
}
12
13
public void setReadXmlService(readXmlService readXmlService)
{
14
this.readXmlService = readXmlService;
15
}
16
}
17
注意:在Spring配置和Quartz集成內容時,有兩點需要注意
1、在<Beans>中不能夠設置default-lazy-init="true",否則定時任務不觸發,如果不明確指明default-lazy-init的值,默認是false。
2、在<Beans>中不能夠設置default-autowire="byName"的屬性,否則后臺會報org.springframework.beans.factory.BeanCreationException錯誤,這樣就不能通過Bean名稱自動注入,必須通過明確引用注入。
比如上例中的parseQuartz就是明確聲明注入的方式
1
<bean id="parseQuartz" class="com.gresoft.components.fileupload.service.ParseFileQuartzOther">
2
<property name="readXmlService" ref="readXmlService" />
3
</bean>
具體錯誤信息如下:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scheduler' defined in file [D:\workspace1\sanitation\web\WEB-INF\classes\spring\quartz.xml]: Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: DB2 SQL error: SQLCODE: -204, SQLSTATE: 42704, SQLERRMC: DB2ADMIN.QRTZ_LOCKS [See nested exception: com.ibm.db2.jcc.b.SqlException: DB2 SQL error: SQLCODE: -204, SQLSTATE: 42704, SQLERRMC: DB2ADMIN.QRTZ_LOCKS]]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1362)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:485)
at java.security.AccessController.doPrivileged(Native Method)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:169)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:170)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:407)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:735)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:369)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:251)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:190)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:45)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:3764)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4216)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:736)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1014)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
at org.apache.catalina.startup.Embedded.start(Embedded.java:822)
at EmbeddedTomcat.startTomcat(EmbeddedTomcat.java:85)
at EmbeddedTomcat.main(EmbeddedTomcat.java:102)
Caused by: org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: DB2 SQL error: SQLCODE: -204, SQLSTATE: 42704, SQLERRMC: DB2ADMIN.QRTZ_LOCKS [See nested exception: com.ibm.db2.jcc.b.SqlException: DB2 SQL error: SQLCODE: -204, SQLSTATE: 42704, SQLERRMC: DB2ADMIN.QRTZ_LOCKS]]
at org.quartz.impl.jdbcjobstore.JobStoreSupport.initialize(JobStoreSupport.java:557)
at org.quartz.impl.jdbcjobstore.JobStoreCMT.initialize(JobStoreCMT.java:144)
at org.springframework.scheduling.quartz.LocalDataSourceJobStore.initialize(LocalDataSourceJobStore.java:133)
at org.quartz.impl.StdSchedulerFactory.instantiate(StdSchedulerFactory.java:1204)
at org.quartz.impl.StdSchedulerFactory.getScheduler(StdSchedulerFactory.java:1355)
at org.springframework.scheduling.quartz.SchedulerFactoryBean.createScheduler(SchedulerFactoryBean.java:687)
at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:582)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1390)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1359)
23 more
Caused by: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: DB2 SQL error: SQLCODE: -204, SQLSTATE: 42704, SQLERRMC: DB2ADMIN.QRTZ_LOCKS [See nested exception: com.ibm.db2.jcc.b.SqlException: DB2 SQL error: SQLCODE: -204, SQLSTATE: 42704, SQLERRMC: DB2ADMIN.QRTZ_LOCKS]
at org.quartz.impl.jdbcjobstore.StdRowLockSemaphore.executeSQL(StdRowLockSemaphore.java:112)
at org.quartz.impl.jdbcjobstore.DBSemaphore.obtainLock(DBSemaphore.java:112)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3655)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInNonManagedTXLock(JobStoreSupport.java:3624)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.cleanVolatileTriggerAndJobs(JobStoreSupport.java:693)
at org.quartz.impl.jdbcjobstore.JobStoreSupport.initialize(JobStoreSupport.java:555)
31 more
Caused by: com.ibm.db2.jcc.b.SqlException: DB2 SQL error: SQLCODE: -204, SQLSTATE: 42704, SQLERRMC: DB2ADMIN.QRTZ_LOCKS
at com.ibm.db2.jcc.b.fg.e(fg.java:1596)
at com.ibm.db2.jcc.b.fg.a(fg.java:1206)
at com.ibm.db2.jcc.a.gb.g(gb.java:140)
at com.ibm.db2.jcc.a.gb.a(gb.java:39)
at com.ibm.db2.jcc.a.w.a(w.java:34)
at com.ibm.db2.jcc.a.vb.g(vb.java:139)
at com.ibm.db2.jcc.b.fg.n(fg.java:1177)
at com.ibm.db2.jcc.b.gg.eb(gg.java:1862)
at com.ibm.db2.jcc.b.gg.d(gg.java:2295)
at com.ibm.db2.jcc.b.gg.V(gg.java:424)
at com.ibm.db2.jcc.b.gg.executeQuery(gg.java:407)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeQuery(DelegatingPreparedStatement.java:92)
at org.quartz.impl.jdbcjobstore.StdRowLockSemaphore.executeSQL(StdRowLockSemaphore.java:92)
36 more
以上就是結合Spring使用Quartz編寫定時任務兩種方式,Spring很好的封裝使用Quartz的細節,第一種方式是利用SPring封裝的Quartz類進行特定方法的實現,第二種是通過透明的使用Quartz達到定時任務開發的目的,總體說第二種對開發人員更方便!