1. 程式人生 > >品Spring:關於@Scheduled定時任務的思考與探索,結果尷尬了

品Spring:關於@Scheduled定時任務的思考與探索,結果尷尬了


非Spring風格的程式碼與Spring的結合


現在的開發都是基於Spring的,所有的依賴都有Spring管理,這沒有問題。

但是要突然寫一些非Spring風格的程式碼時,可能會很不習慣,如果還要和Spring風格的程式碼結合起來的話,就會稍顯麻煩。

因為非Spring風格的程式碼不由Spring管理,所以Spring不會給我們注入依賴,相反,我們要自己去Spring中拿取依賴。

所以首先目標就是要獲取Spring容器,即ApplicationContext,方法通常如下圖01:

 

定義一個類實現ApplicationContextAware,類中定義一個靜態的ApplicationContext欄位,Spring會把容器注入到這個靜態欄位。


由於類的靜態欄位在JVM中一直存在,這樣ApplicationContextUtils這個類就可以在非Spring風格的程式碼裡使用Spring管理的bean了。


若用於定時任務是否有潛在的問題


Spring自帶的定時任務,非常好用,而且我很早就用過,具體時間已經記不清了。

我依稀記得以前好像覺得容器還沒有啟動完成時,定時任務就有可能被觸發。就姑且認為是這樣吧,當然也可能不是。

如果我的定時任務執行的程式碼是非Spring風格的,我自然需要自己去new例項,如下圖02:

 

如果這個非Spring風格的程式碼恰好又要使用Spring管理的bean,那就是剛剛上面提到的方式,如下圖03:


 

可以看到SimpleService是Spring管理的bean,SimpleTask卻不是,所以只能在構造方法裡使用容器的getBean方式獲取。

這種方式通常是沒有問題的,我們也都是這樣用的。但是要把它放到定時任務裡呢?

會不會出現定時任務觸發的較早,此時ApplicationContextUtils類裡的靜態欄位ApplicationContext還沒有被注入呢?

如果真這樣的話,那可就空指標了。那到底會不會這樣呢,一起來探索發現下吧。


探索與發現,沒有頻道


我比較認同這個觀點:

當一個人什麼都不知道的時候,他覺得自己什麼都懂,老想出來指點江山。

當一個人隨著學習知道的越多,他發現自己懂的越少,反而不敢隨便亂說。


其實就是,知道的越多,問題就越多,隨之而來的困惑也就越多。

我寫完16篇《品Spring》文章,知道了bean定義註冊的順序、bean例項化的順序、bean後處理器應用的順序都和本文描述的問題有關。

所以我也不敢冒然亂說,只能逐步測試逼近答案,這就是典型的知道的“太多了”的煩惱,哈哈。

其實本文的問題就是一個先後順序的問題,如果定時任務先觸發就會產生空指標,如果靜態欄位先注入,就不會有空指標。

而我選擇了相信有空指標,完全是吃瓜群眾幸災樂禍的心理,嘻嘻。

所以我就想辦法安排空指標的出現。甚至“處心積慮”,直至使出渾身解數。

一、讓定時任務的bean定義註冊早於ApplicationContextUtils

拋開依賴不說,例項化的順序就是bean定義註冊的順序。

bean定義註冊的順序怎麼確定呢?單就掃描jar包而言,就是包名和類名的字母順序。

因此,我的安排如下圖04:

 

最終bean定義的順序符合預期,如下圖05:

 

這說明bean例項化的順序是,先例項化定時任務,再例項化ApplicationContextUtils。保證了定時任務在前。

遺憾的是,我安排的空指標沒有出現,一切是正常的,定時任務中可以獲取到靜態欄位的值。

二、讓定時任務以最快的速度觸發

因為這兩個bean定義是挨著的,所以例項化也是挨著的。會不會是例項化執行的太快了?

由於例項化的速度無法控制,所以就加快定時任務的觸發速度,試試看。

改成1秒就觸發,如下圖06:

 

哎,遺憾的是還是一切正常,我太想看到報錯了,哈哈,繼續使“陰招”。

三、讓ApplicationContextUtils的例項化過程卡住

定時任務肯定先例項化好,然後才會去例項化ApplicationContextUtils。

這次想辦法讓後者卡住,這樣定時任務該先執行了吧。小樣,我還治不了你啦。

因為定時任務是在單獨的執行緒池中執行,所以讓主執行緒睡一會即可,如下圖07:

 

主執行緒確實卡住了,遺憾的是還是一切正常。


深入虎穴,不為虎子


ApplicationContext的注入和定時任務的處理都是由bean後處理器完成的。

所以把容器中的後處理器都輸出來看看,如下圖08:

 

可以看到共有12個,顯示的順序就是它們被應用的順序。

也就是說對於每一個bean例項的建立,都會應用這12個,且按如圖順序應用。

只不過每個bean後處理器只處理自己關注的bean,對於不關注的不起作用而已。

而且這12個的順序只對單個bean有意義,對於不同的bean,沒有意義。

因為在測試時,我發現每次必須等容器啟動好後,定時任務才開始執行。

所以只能去看處理定時任務的bean後處理器原始碼了,即ScheduledAnnotationBeanPostProcessor這個類。

於是就從上往下看原始碼,當看到這個方法後,我似乎明白了,如下圖09:

 

這是一個事件的回撥方法,引數是ContextRefreshed事件物件,說明在容器啟動完成後會呼叫這個方法。

再看看方法體,就一句程式碼,finishRegistration,完成註冊,說明在容器沒有啟動好之前,這個註冊是不會完成的。

其實已經表達的很清楚了,只有在容器啟動完成後,定時任務才會完成註冊,才會開始被排程。

然後再看看完成註冊方法,它的最後一句程式碼如下圖10:

 

這個方法名很親切吧,就是和初始化相關的。

然後再進到這個方法裡看看,如下圖11:

 

也只有一句程式碼,就是排程任務。哦,現在才開始排程。之前的只是註冊任務,並沒有排程。


慘遭打臉?其實並沒有


我仔細看了幾遍原始碼,發現寫的很有特點,既支援容器啟動好後觸發定時任務,也支援容器啟動過程中的及時觸發。

只不過現在預設是前者而已。所以我懷疑以前可能就是及時觸發,後來可能覺得不太合適,就進行了改造,成了現在這樣子。

這既是探索與發現精神,也是好奇精神,就是它促使了我們向前發展,去了解更多的未知領域。

>>> 品Spring系列文章 <<<

 

品Spring:帝國的基石

品Spring:bean定義上梁山

品Spring:實現bean定義時採用的“先進生產力”

品Spring:註解終於“成功上位”

品Spring:能工巧匠們對註解的“加持”

品Spring:SpringBoot和Spring到底有沒有本質的不同?

品Spring:負責bean定義註冊的兩個“排頭兵”

品Spring:SpringBoot輕鬆取勝bean定義註冊的“第一階段”

品Spring:SpringBoot發起bean定義註冊的“二次攻堅戰”

品Spring:註解之王@Configuration和它的一眾“小弟們”

品Spring:bean工廠後處理器的呼叫規則

品Spring:詳細解說bean後處理器

品Spring:對@PostConstruct和@PreDestroy註解的處理方法

品Spring:對@Resource註解的處理方法

品Spring:對@Autowired和@Value註解的處理方法

品Spring:真沒想到,三十步才能完成一個bean例項的建立

 

>>> 熱門文章集錦 <<<

 

畢業10年,我有話說

【面試】我是如何面試別人List相關知識的,深度有點長文

我是如何在畢業不久只用1年就升為開發組長的

相關推薦

Spring關於@Scheduled定時任務思考探索結果尷尬

非Spring風格的程式碼與Spring的結合現在的開發都是基於Spring的,所有的依賴都有Spring管理,這沒有問題。但是要突然寫一些非Spring風格的程式碼時,可能會很不習慣,如果還要和Spring風格的程式碼結合起來的話,就會稍顯麻煩。因為非Spring風格的程式碼不由Spring管理,所以Spr

spring-boot ---Scheduled 定時任務

package com.shi.snyc; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; imp

spring batch結合定時任務記錄每一次結果

1.當我們不知道程式怎麼跑的時候是十分可怕的,所有對於定時任務,我們需要把每一次的執行細節,傳入的引數,執行的結果等儲存到資料庫中。那麼怎樣儲存那。我這裡給出一個方案。springbatch。2.專案基礎springboot,maven,druid。(1)maven中引入ja

定時任務quartzspring整合(springboot)

設定beanFactory以及建立job package cm.wesure.task; import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.BeansException; import org

一張圖讓你秒懂Spring @Scheduled定時任務的fixedRate,fixedDelay,cron執行差異

https://blog.csdn.net/applebomb/article/details/52400154   看字面意思容易理解,但是任務執行長度超過週期會怎樣呢? 不多說,直接上圖: 測試程式碼: import java.text.DateFormat; imp

Spring中的定時任務@scheduled

使用@scheduled實現定時任務 A 任務會阻塞 @Component @EnableScheduling public class ATask implements SchedulingConfigurer { @Scheduled(cron="0/10

spring @Scheduled 定時任務

@Service public class TimerTask{ private static final Logger logger = LoggerFactory.getLogger(TimerT

4.7 基於Spring註解的定時任務(@Schedule) > 我的程式猿之路第三十七章

Cron表示式是一個字串,字串以5或6個空格隔開,分為6或7個域,每一個域代表一個含義,Cron有如下兩種語法格式:  Seconds Minutes Hours DayofMonth Month DayofWeek Year或 Seconds Minutes Hours DayofMonth Month

spring如何設定定時任務詳解(@Scheduled)

目錄 一:註解方式配置定時任務: 二:@Scheduled 三:原理簡介 四:其他 以前用過這個註解實現定時任務,但是隻是使用,現在做專案又用到了這個功能,系統的學習一下~ spring定

Spring @Scheduled定時任務動態修改cron引數

  Spring框架自3.0版本起,自帶了任務排程功能,好比是一個輕量級的Quartz,而且使用起來也方便、簡單,且不需要依賴其他的JAR包。秉承著Spring的一貫風格,Spring任務排程的實現同時支援註解配置和XML配置兩種方式。   再來談談變態的專案需求:我們正在做一個智慧數字電錶的資料採集專案,

spring @scheduled 定時任務註解使用

Spring @scheduled 用法: 定時任務註解 需要新增的如下圖所示: 一、新增配置 1. xmlns:task="http://www.springframework.org/schema/task" 2. http://www.springframe

spring @scheduled 定時任務詳解

使用@scheduled定時任務有兩種方式,一種是直接@scheduled(cron=”0 0 0 ? * * “) 還有一種是使用xml配置 對於這兩種方式,首先需要在Spring配置檔案xmlns加入 xmlns:task="http://www.

Spring Boot使用方法小札(2)執行定時任務

在Spring Boot中要定時執行一些任務可以不必要使用執行緒來實現,它為我們提供了一種方法來簡化任務的定時執行,這種方式是建立在@EnableScheduling和@Scheduled上的。 首先我們需要先建立一個需要定時執行的任務,如下: @Com

去哪網實習總結開發定時任務(JavaWeb)

pri simple mod 節點 easy run dsm 16px 發送郵件 本來是以做數據挖掘的目的進去哪網的,結構卻成了系統開發。。。 只是還是比較認真的做了三個月,老師非常認同我的工作態度和成果。。。 實習立即就要結束了。總結一下幾點之前沒有註意過的變成

linux 定時任務atcrontab

linux at 定時任務 crontab 1、at一次性任務1.1 命令at安裝 從文件或標準輸入中讀取命令並在將來的一個時間執行,只執行一次。at的正常執行需要有守護進程atd.#安裝at yum install -y at #啟動守護進程 service atd s

Spring+Quartz實現定時任務的配置方法

detail 包含 範例 empty beans ref tail 可選 creat 1、Scheduler的配置 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean"&g

Spring整合Quartz定時任務 在集群、分布式系統中的應用(Mysql數據庫環境)

foreign log ride bigint post 業務 設置 ade 營業額 Spring整合Quartz定時任務 在集群、分布式系統中的應用(Mysql數據庫環境) 轉載:http://www.cnblogs.com/jiafuwei/p/6145280.

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

log cor alt 放置 這一 表達 mod 建數據庫 strac 1、定時任務的必要性:定時任務在應用中的重要性不言而喻,大多是應用,特別是金融應用更是離不開定時任務,能用定時任務來處理異常訂單,完成跑批,定時活動(雙11)等。在初期應用的訪問量並不是那麽大,

spring boot啟動定時任務

spring logs 例如 info 一次 work frame mage http 1、 定時任務在Spring Boot中的集成 在啟動類中加入開啟定時任務的註解: 在SpringBoot中使用定時任務相當的簡單。首先,我們在啟動類中加入@EnableScheduli

spring多個定時任務quartz配置

ram 至少 utf-8 list 表達 lse 第一個 span cron spring多個定時任務quartz配置 1 <?xml version=”1.0″ encoding=”UTF-8″?> 2 <beans xmlns=”http:/