兩種方式部署定時任務(wù),Spring整合Quartz,Spring整合task(java后臺)

(Notice:以下所有經(jīng)驗也是我根據(jù)網(wǎng)上的經(jīng)驗整理的,如有侵權(quán)可以聯(lián)系我刪除,歡迎交流和溝通,Wx:IT_Ezra,QQ 654303408。 有問題討論也可聯(lián)系我。)

(Tips:我是第一次開發(fā),一個剛畢業(yè)的java工程師,我覺得我并非天賦異稟,我能學會,相信聰敏的你,一定可以)

(PS:定時任務(wù)是一個非常常見的功能,在我們進行系統(tǒng)開發(fā)中,經(jīng)常會用到,有點類似于OS中的批處理。對于一些實時性不高的任務(wù),比如退款,消息推送,會用到定時任務(wù)。)

首先需要使用的jar包:用maven在pom.xml中配置。版本有很多哦,自己可以去世界庫找一個。

 <dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>   
  • 方式一(相對代碼較多):通過XML文件配置。通過上下文配置邏輯清晰。流程清晰。通常情況下,我們的spring配置文件命名為applicationContext.xml,并且存放在resource文件夾下。我們不妨在resource文件夾下新建一個spring文件夾。這個文件夾可以專門去配置一些spring集成框架。與spring是同級的。(為什么不配置到springMVC,問這個問題的同學,可以去了解一下springMVC的原理。因為SpringMVC是一個servlet的框架,是作用于Web層,controller等等。而類似于quartz等框架是與SpringMVC平級的,是對定時任務(wù)進行管理,作用于Conponent,不屬于附屬關(guān)系。)然后新建一個XML文件 ,建議命名為:spring-scheduler.xml。

項目結(jié)構(gòu)圖如下

image.png

先上代碼。提前說一點,每一個class對應(yīng)的****FactoryBean是對應(yīng)的。一共有三個, 要么都用***Bean,要么都用****FactoryBean。用混的情況下是會報錯的。(曾經(jīng)在eclipse沒報錯,但是在idea報錯了)

<?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-4.0.xsd">
    <!-- 申明執(zhí)行任務(wù)的類 -->
    <bean id="messageSendJob" class="com.job.MessageSendJob"></bean>

    <!-- 申請線程池 -->
    <bean id="schedulerExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <property name="corePoolSize" value="10" />
        <property name="maxPoolSize" value="100" />
        <property name="queueCapacity" value="500" />
    </bean>

    <!-- 調(diào)度業(yè)務(wù) -->
    <bean id="messageSendJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="messageSendJob" />
        <property name="targetMethod" value="message" />
    </bean>

    <!-- 觸發(fā)器 -->
    <bean id="messageSendCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        <property name="jobDetail" ref="messageSendJobDetail" />
        <property name="cronExpression" value="* 0/20 * * * ?" />
    </bean>

    <!-- 設(shè)置調(diào)度 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="triggers">
            <list>
                <ref bean="messageSendCronTrigger" />
            </list>
        </property>
        <property name="taskExecutor" ref="schedulerExecutor" />
    </bean>
</beans>
  • 該部分是spring-scheduler.xml配置文件的內(nèi)容。層級關(guān)系也十分明顯,配置內(nèi)容也很簡單。其中要介紹的就是cron表達式,可以自行百度。corn從左到右(用空格隔開):* * * * * ? * 通常情況下只使用六位,也就是 * * * * * ? 。最后一位用“?” , 下面有解釋

  • 秒 分 小時 月份中的日期 月份 星期中的日期 年份

  • 字段 允許值 允許的特殊字符

  • 秒(Seconds) 0~59的整數(shù) , - * / 四個字符

  • 分(Minutes) 0~59的整數(shù) , - * / 四個字符

  • 小時(Hours) 0~23的整數(shù) , - * / 四個字符

  • 日期(DayofMonth) 1~31的整數(shù)(但是你需要考慮你月的天數(shù)) ,- * ? / L W C 八個字符

  • 月份(Month) 1~12的整數(shù)或者 JAN-DEC , - * / 四個字符

  • 星期(DayofWeek) 1~7的整數(shù)或者 SUN-SAT (1=SUN) , - * ? / L C # 八個字符

  • 年(可選,留空)(Year) 1970~2099 , - * / 四個字符

  • (1)* :表示匹配該域的任意值。假如在Minutes域使用*, 即表示每分鐘都會觸發(fā)事件。

  • (2)? :只能用在DayofMonth和DayofWeek兩個域。它也匹配域的任意值,但實際不會。因為- ####DayofMonth和DayofWeek會相互影響。例如想在每月的20日觸發(fā)調(diào)度,不管20日到底是星期幾,則只能使用如下寫法: 13 13 15 20 * ?, 其中最后一位只能用?,而不能使用,如果使用表示不管星期幾都會觸發(fā),實際上并不是這樣。

  • (3)- :表示范圍。例如在Minutes域使用5-20,表示從5分到20分鐘每分鐘觸發(fā)一次

  • (4)/ :表示起始時間開始觸發(fā),然后每隔固定時間觸發(fā)一次。例如在Minutes域使用5/20,則意味著5分鐘觸發(fā)一次,而25,45等分別觸發(fā)一次.

  • (5), :表示列出枚舉值。例如:在Minutes域使用5,20,則意味著在5和20分每分鐘觸發(fā)一次。

  • (6)L :表示最后,只能出現(xiàn)在DayofWeek和DayofMonth域。如果在DayofWeek域使用5L,意味著在最后的一個星期四觸發(fā)。

  • (7)W :表示有效工作日(周一到周五),只能出現(xiàn)在DayofMonth域,系統(tǒng)將在離指定日期的最近的有效工作日觸發(fā)事件。例如:在 DayofMonth使用5W,如果5日是星期六,則將在最近的工作日:星期五,即4日觸發(fā)。如果5日是星期天,則在6日(周一)觸發(fā);如果5日在星期一到星期五中的一天,則就在5日觸發(fā)。另外一點,W的最近尋找不會跨過月份 。

  • (8)LW :這兩個字符可以連用,表示在某個月最后一個工作日,即最后一個星期五。

  • (9)# :用于確定每個月第幾個星期幾,只能出現(xiàn)在DayofMonth域。例如在4#2,表示某月的第二個星期三。

其次一個需要介紹的就是具體的調(diào)度任務(wù),也就是如下代碼塊

<!-- 調(diào)度業(yè)務(wù) -->
    <bean id="messageSendJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
        <property name="targetObject" ref="messageSendJob" />
        <property name="targetMethod" value="message" />
    </bean>

bean的id自己命名,property中name自己命名。而ref中的調(diào)度業(yè)務(wù)。 我的調(diào)度業(yè)務(wù)如下

package com.job;

/**
 * @ author ezra
 * @ date 2019/2/18 15:56
 */

import com.service.MessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

/**
 * 消息推送定時任務(wù)
 * @author zjj
 * @date 2019-02-13
 */
@Component
public class MessageSendJob {

    private static final Logger logger = LoggerFactory.getLogger(MessageSendJob.class);

    /**
     * 每隔5分鐘查詢一次是否有消息
     */
    @Autowired
    private MessageService MessageService;

    public void message() {
        logger.info("【begin】執(zhí)行批量消息推送定時任務(wù)");
            // 執(zhí)行批量消息推送操作
            MessageService.messageAll();
        logger.info("【end】執(zhí)行批量消息推送定時任務(wù)");
    }


    /**
     * 每隔一星期設(shè)置無效form(暫時不實現(xiàn))
     */
/*
    public void templete() {
        logger.info("【begin】執(zhí)行批量formid失效刪除定時任務(wù)");
        // 為了防止定時任務(wù)多線程并行執(zhí)行時出現(xiàn)退款多次的情況,對過程加上互斥鎖保證該任務(wù)串行執(zhí)行
        // 如果后期應(yīng)用改為多機部署,需要將此處改為分布式鎖或者由分布式任務(wù)調(diào)度系統(tǒng)協(xié)調(diào)串行執(zhí)行
        synchronized (OrderRefundJob.class) {
            // 執(zhí)行批量退款操作
            MessageService.templateDelete();
        }
        logger.info("【end】執(zhí)行批量formid失效刪除定時任務(wù)");
    }
*/
}

完成以上操作之后,基本上定時任務(wù)已經(jīng)配置完成。接下來最后一步,是通過web.xml去加載,應(yīng)該每個人都知道applicationContext.xml的加載吧,在后面添加classpath:spring/spring-scheduler.xml即可。

  <!-- 獲取requst respose對象-->
    <listener>
        <listener-class>
            org.springframework.web.context.request.RequestContextListener
        </listener-class>
    </listener>
    <!-- 利用Spring提供的ContextLoaderListener監(jiān)聽器去監(jiān)聽ServletContext對象的創(chuàng)建,并初始化WebApplicationContext對象 -->
   <listener>
       <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>
   <!-- Context Configuration locations for Spring XML files(默認查找/WEB-INF/applicationContext.xml) -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:applicationContext.xml,classpath:spring/spring-scheduler.xml</param-value>
    </context-param>

方法二,非常暴力,在application里面掃描添加掃描項<task:annotation-driven/>

通過注解完成。@Scheduled 后面接cron表達式。相當于集成spring-task

@Component
public class OrderRefundJob {

    private static final Logger logger = LoggerFactory.getLogger(OrderRefundJob.class);

    @Autowired
    private RefundService RefundService;


    @Scheduled(cron = "* 0/5 *  * * ?")
    public void refund() {
        logger.info("【begin】執(zhí)行批量退款定時任務(wù)開始");
        // 執(zhí)行批量退款操作
        RefundService.refundAll();
        logger.info("【end】執(zhí)行批量退款定時任務(wù)結(jié)束");
    }

}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容