(Notice:以下所有經(jīng)驗也是我根據(jù)網(wǎng)上的經(jīng)驗整理的希坚,如有侵權(quán)可以聯(lián)系我刪除,歡迎交流和溝通陵且,Wx:IT_Ezra裁僧,QQ 654303408个束。 有問題討論也可聯(lián)系我。)
(Tips:我是第一次開發(fā)聊疲,一個剛畢業(yè)的java工程師茬底,我覺得我并非天賦異稟,我能學(xué)會获洲,相信聰敏的你阱表,一定可以)
(PS:定時任務(wù)是一個非常常見的功能,在我們進(jìn)行系統(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悦昵,問這個問題的同學(xué),可以去了解一下springMVC的原理晌畅。因為SpringMVC是一個servlet的框架但指,是作用于Web層,controller等等抗楔。而類似于quartz等框架是與SpringMVC平級的棋凳,是對定時任務(wù)進(jìn)行管理,作用于Conponent连躏,不屬于附屬關(guān)系剩岳。)然后新建一個XML文件 ,建議命名為:spring-scheduler.xml入热。
項目結(jié)構(gòu)圖如下
先上代碼拍棕。提前說一點晓铆,每一個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表達(dá)式讳侨,可以自行百度呵萨。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)用改為多機(jī)部署,需要將此處改為分布式鎖或者由分布式任務(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(默認(rèn)查找/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表達(dá)式。相當(dāng)于集成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é)束");
}
}