SpringBoot基於數據庫的定時任務實現


在我們平時開發的項目中,定時任務基本屬於必不可少的功能,那大家都是怎么做的呢?但我知道的大多都是靜態定時任務實現。

基於注解來創建定時任務非常簡單,只需幾行代碼便可完成。實現如下:

 

[Java] 純文本查看 復制代碼
?
01
02
03
04
05
06
07
08
09
10
11
<font style= "color:rgb(77, 77, 77)" ><font face= "&quot;" ><font style= "font-size:16px" > @Configuration
@EnableScheduling
public class SimpleScheduleTask {
  
     //10秒鍾執行一次
     @Scheduled (cron = "0/10 * * * * ?" )
     private void tasks() {
         System.out.println( "【定時任務】 每10秒執行一次!" );
     }
}
</font></font></font>

 

Cron表達式參數分別表示(從左到右):
秒(0~59) 如0/5表示每5秒
分(0~59)
時(0~23)
日(0~31) 月的某一天
月(0~11)
周幾( 可填1-7 或 SUN/MON/TUE/WED/THU/FRI/SAT)

就上面幾行代碼,就能搞定一個定時任務。顯然,使用Scheduled 確實特別的方便,但有很大的缺點和局限,就是當我們調整了執行計划的時間時,需要重啟服務才能生效,這就有些不方便。為了達到實時生效的效果,可以通過數據庫來動態實現定時任務。

基於數據庫的動態定時任務實現

將定時任務配置在數據庫,啟動項目的時候,用mybatis讀取數據庫,實例化對象,並設定定時任務。如果需要新增,減少,修改定時任務,僅需要修改數據庫資料,並重啟項目即可,無需改代碼。

 

[Java] 純文本查看 復制代碼
?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
<font style= "color:rgb(77, 77, 77)" ><font face= "&quot;" ><font style= "font-size:16px" >Lazy(value = false )
@Component
public class ScheduleTask implements SchedulingConfigurer {
  
     protected static Logger logger = LoggerFactory.getLogger(ScheduleTask. class );
     private SimpleDateFormat sdf= new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" );
  
     @Autowired
     private ScheduleTaskMapper scheduleTaskMapper;
  
     @Override
     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
         List<ScheduleTask> tasks = getAllScheduleTasks();
         logger.info( "【定時任務啟動】 啟動任務數:" +tasks.size()+ "; time=" +sdf.format( new Date()));
  
         //校驗數據
         checkDataList(tasks);
         //通過校驗的數據執行定時任務
         int count = 0 ;
         if (tasks.size()> 0 ) {
             for ( int i = 0 ; i < tasks.size(); i++) {
                 try {
                     taskRegistrar.addTriggerTask(getRunnable(tasks.get(i)), getTrigger(tasks.get(i)));
                     count++;
                 } catch (Exception e) {
                     logger.error( "task start error:" + tasks.get(i).getClassName() + ";" + tasks.get(i).getMethodName() + ";" + e.getMessage());
                 }
             }
         }
         logger.info( "started task number=" +count+ "; time=" +sdf.format( new Date()));
     };
  
   /**
   * 獲取要執行的所有任務
   * @return
   */
     private List<ScheduleTask> getAllScheduleTasks() {
         ScheduleTaskExample example= new ScheduleTaskExample();
         example.createCriteria().andIsDeleteEqualTo(( byte ) 0 );
         return scheduleTaskMapper.selectByExample(example);
     }
   
   /**
   * 獲取Runnable
   *
   * @param task
   * @return
   */
     private Runnable getRunnable(ScheduleTask task){
         return new Runnable() {
             @Override
             public void run() {
                 try {
                     Object obj = SpringUtil.getBean(task.getClassName());
                     Method method = obj.getClass().getMethod(task.getMethodName(), null );
                     method.invoke(obj);
                 } catch (InvocationTargetException e) {
                     logger.error( "refect exception:" +task.getClassName()+ ";" +task.getMethodName()+ ";" + e.getMessage());
                 } catch (Exception e) {
                     logger.error(e.getMessage());
                 }
             }
         };
     }
  
   /**
   * 獲取Trigger
   *
   * @param task
   * @return
   */
     private Trigger getTrigger(ScheduleTask task){
         return new Trigger() {
             @Override
             public Date nextExecutionTime(TriggerContext triggerContext) {
                 //將Cron 0/1 * * * * ?
                 CronTrigger trigger = new CronTrigger(task.getCron());
                 Date nextExec = trigger.nextExecutionTime(triggerContext);
                 return nextExec;
             }
         };
     }
   
   /**
   * 校驗數據
   *
   * @param list
   * @return
   */
     private List<ScheduleTask> checkDataList(List<ScheduleTask> list) {
         String msg= "" ;
         for ( int i= 0 ;i<list.size();i++){
             if (!checkOneData(list.get(i)).equalsIgnoreCase( "ok" )){
                 msg+=list.get(i).getTaskName()+ ";" ;
                 list.remove(list.get(i));
                 i--;
             };
         }
         if (!StringUtils.IsEmpty(msg)){
             msg= "未啟動的任務:" +msg;
             logger.error(msg);
         }
         return list;
     }
  
   /**
   * 按每一條校驗數據
   *
   * @param task
   * @return
   */
     private String checkOneData(ScheduleTask task){
         String result= "ok" ;
         Class cal= null ;
         try {
             cal = Class.forName(task.getClassName());
             Object obj =SpringUtil.getBean(cal);
             Method method = obj.getClass().getMethod(task.getMethodName(), null );
             String cron=task.getCron();
             if (StringUtils.isBlank(cron)){
                 result= "no found the cron:" +task.getTaskName();
                 logger.error(result);
             }
         } catch (ClassNotFoundException e) {
             result= "not found the class:" +task.getClassName()+ e.getMessage();
             logger.error(result);
         } catch (NoSuchMethodException e) {
             result= "not found the method:" +task.getClassName()+ ";" +task.getMethodName()+ ";" + e.getMessage();
             logger.error(result);
         } catch (Exception e) {
           logger.error(e.getMessage());
          }
         return result;
     }
</font></font></font>

 

數據庫配置

<ignore_js_op>

運行的結果

<ignore_js_op>

這樣我們可以通過直接修改數據庫,執行周期就會改變,並且不需要我們重啟應用,十分方便。

更多技術資訊可關注:itheimaGZ獲取


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM