在維護一個老舊專案時,發現其排程任務採用 Spring 的 TimerFactoryBean 實現,而非主流的 Quartz。由於資料稀少,起初為了確認任務是否會並行執行,特意研讀原始碼,發現其底層採用 JDK Timer,確保上一個任務未結束時不會啟動下一個,這點符合預期。
典型配置如下:
<bean id="myTask" class="xx.xx.MyTask" />
<bean id="scheduleTask1" class="org.springframework.scheduling.timer.ScheduledTimerTask">
<property name="delay" value="10000" />
<property name="period" value="10000" />
<property name="timerTask">
<ref local="myTask" />
</property>
</bean>
<bean id="timerFactoryBean" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduleTask1" />
</list>
</property>
</bean>
任務雖配置正確,但運行一段時間後頻繁自行停止,毫無錯誤日誌。初步懷疑未捕獲異常導致線程退出,但自定義任務類 MyTask 已全段 try-catch。排查線程死鎖、分析堆疊資訊均無果。
為驗證框架層面的異常處理能力,分別在兩種實現中拋出未捕獲異常:
由此推斷,TimerFactoryBean 內部缺乏健壯的異常隔離機制,一旦底層 Timer 線程因異常終結,整個調度鏈路隨之崩潰。
TimerFactoryBean 存在設計缺陷,不適合生產環境的長期排程任務。 強烈建議遷移至 Spring 整合的 Quartz 框架,其具備成熟的錯誤恢復、叢集支援與彈性配置,能有效避免此類「靜默失效」風險。