1. 程式人生 > >java web定時任務---quartz

java web定時任務---quartz

寫在前面:

  前面有簡單的記錄下Timer定時的用法,但是在此次專案中,選擇的是quartz來完成定時操作任務的。兩者都可以完成定時操作,但是spring可以整合quartz,並且配置起來也比較簡便,還可以同時跑多個任務。就選擇了quartz,quartz的用法也很強大,這裡也是簡單的記錄下。

  第一步還是需要寫自己的任務類,如果有涉及到對資料庫的增刪改查操作,就按照正常的action,service ,dao的三層來編寫方法就好,只不過現在不是通過頁面傳送請求來呼叫action,而是通過quartz的定時來呼叫action操作。

  1.編寫自己的任務類:

@Controller("TimerTask")
public class TimerTask {
    @Resource
    private ProjectWorkItemAssignmentService projectWorkItemAssignmentService;
    
    /**
     * 每天12:00去自動暫停ProjectWorkItemAssignment表中在執行的workItem
     * 以及去自動暫停WorkHoursRecord表中當天在執行的workItem
     */
    public void autoPauseWorkItemOne() throws Exception{
        projectWorkItemAssignmentService.autoPauseWorkItemOne();
    }

    /**
     * 每天13:30去自動開啟ProjectWorkItemAssignment表中在執行的workItem
     * 以及去自動開啟WorkHoursRecord表中當天在執行的workItem
     */
    public void autoStartWorkItem() throws Exception{
        projectWorkItemAssignmentService.autoStartWorkItem();
    }

    /**
     * 每天17:30去自動暫停ProjectWorkItemAssignment表中在執行的workItem
     * 以及去自動暫停WorkHoursRecord表中當天在執行的workItem
     */
    public void autoPauseWorkItemTwo() throws Exception{
        projectWorkItemAssignmentService.autoPauseWorkItemTwo();
    }
}

  這裡的任務類,我是當做action來寫的,然後裡面的業務方法,根據自己的需求來即可,這裡只是簡單的列舉一下子,後面對應的service,dao的業務就不具體上程式碼了

  2.編寫配置檔案,這裡我用到的是使用配置檔案的形式來配置程式執行的週期以及頻率的(可以使用程式碼的,自己下去查閱資料),由於spring可以整合quartz,還是挺方便的。

我們可以把quartz的配置寫在applicationContext.xml檔案裡面,也可以單獨拿出來寫一個,然後匯入到applicationContext.xml檔案中。這裡就單獨寫一個檔案。

  applicationContext-quartz.xml(這裡我自己配置了三個定時任務,可以根據自己的需要去開啟配置)

<?xml version="1.0" encoding="UTF-8"?>
<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-3.0.xsd">


    <bean id="jobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="TimerTask"   />   <!-- 配置排程的定時任務 -->
        <property name="targetMethod" value="autoPauseWorkItemOne" />   <!-- 配置排程定時任務中的方法 -->
        <property name="concurrent"   value="false"   />   <!-- 是否併發執行 -->
    </bean>

    <bean id="jobDetail2" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="TimerTask"   />   <!-- 配置排程的定時任務 -->
        <property name="targetMethod" value="autoStartWorkItem" />   <!-- 配置排程定時任務中的方法 -->
        <property name="concurrent"   value="false"   />   <!-- 是否併發執行 -->
    </bean>

    <bean id="jobDetail3" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="TimerTask"   />   <!-- 配置排程的定時任務 -->
        <property name="targetMethod" value="autoPauseWorkItemTwo" />   <!-- 配置排程定時任務中的方法 -->
        <property name="concurrent"   value="false"   />   <!-- 是否併發執行 -->
    </bean>

    <!-- 觸發器 配置定時任務的排程的時間 -->
    <bean id="workItemTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="jobDetail" />
        <property name="cronExpression">
            <value>0 0 12 * * ? </value><!--  [秒] [分] [時] [日] [月] [年] 每天12點觸發-->
        </property>
    </bean>

    <bean id="workItemTrigger2" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="jobDetail2" />
        <property name="cronExpression">
            <value>0 30 13 * * ? </value><!--  [秒] [分] [時] [日] [月] [年] 每天13:30點觸發-->
        </property>
    </bean>

    <bean id="workItemTrigger3" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="jobDetail3" />
        <property name="cronExpression">
            <value>0 30 17 * * ? </value><!--  [秒] [分] [時] [日] [月] [年] 每天17:30點觸發-->
        </property>
    </bean>

    <!--定義排程器 --><!-- lazy-init='false'容器啟動就會執行排程程式 autowire="no"-->
    <bean id="workItemscheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false" autowire="no">
        <property name="triggers">
            <list>
                <ref bean="workItemTrigger" />
                <ref bean="workItemTrigger2" />
                <ref bean="workItemTrigger3" />
            </list>
        </property>
    </bean>
    
</beans>

  記得在spring的配置檔案中加入quartz的配置檔案

  applicationContext.xml:

<import resource="classpath:configs/applicationContext-quartz.xml"/>

  對於呼叫任務類有兩種方式,(使用JobDetailBean來呼叫某個類,)這裡我用的是直接執行某個類的哪一個方法,比較方便。

  其實在剛開始編寫的過程中也遇到各種問題,下面也簡單的記錄下。

  當任務類是service層的類時,無法使用getCurrentSession()來獲取session,程式不報錯,直接卡在那裡。然後是可以使用openSession()來重新開啟一個session的,但是對於增刪改,每次都需要自己手動進行session的關閉以及事務的提交,不是很方便。當時一直沒有找到問題所在,為什麼不可以使用getCurrentSession,雖然quartz是新開了一個執行緒,但是getCurrentSession()不是獲取當前執行緒的session,如果沒有就重新開一個麼?為什麼獲取不到呢?很是鬱悶.......後來考慮到了是不是專案配置的session的生命週期有影響,因為專案延長了session的生命週期,如下:

<!-- 配置Spring的OpenSessionInViewFilter,以解決懶載入問題  -->
    <filter>
        <filter-name>OpenSessionInViewFilter</filter-name>
        <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
    </filter>

決定還是按照規矩來,不要把service層的類直接當任務類去呼叫,而是改用任務類為action,哇咔咔咔,竟然成功了,可以使用getCurrentSession來獲取session了,真的是折磨.....

  所以寫程式碼還是要多多試試,多多實踐下,然後在試的過程中一不小心就會給你大大的驚喜!!!

  雖然記錄的很簡單,但是總比不記錄的要好,恩就這樣安慰自己,這個樣子也是很好的............................ 

  補充一下一個獲取sessionFactory的方式:

WebApplicationContext wac = ContextLoader.getCurrentWebApplicationContext();
SessionFactory factory=wac.getBean(SessionFactory.class);
Session session=factory.openSession();