springboot + schedule

參考文章:https://blog.csdn.net/sinianliushui/article/details/78841713html

參考文章: https://blog.csdn.net/hao7030187/article/details/79077464java

參考文章:https://www.cnblogs.com/domi22/p/9418433.htmlweb

 

springboot的SchedulerTask相對Quartz來講,簡單方便,可試用於小型的job處理。redis

因無法持久化所以不支持分佈式部署,和動態數據源配置。spring

若是要segmentfault

1、簡易配置springboot

1. 開啓定時任務,在啓動類添加如下註解併發

@EnableScheduling

2. 建立併發配置,併發線程app

@Component
public class SchedulerConfig implements SchedulingConfigurer {

    /**
     * 設置定時任務
     * @param scheduledTaskRegistrar
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
    }
}

3. 建立scheduler,如下是沒5秒觸發一次,cron表達式有cron在線生成器能夠用dom

@Component
@Slf4j
public class SchedulerTask {

    @Scheduled(cron="0/5 * * * * ? ")
    public void testTask(){
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.debug(Thread.currentThread() + "  " + sdf.format(new Date()));
    }
    @Scheduled(cron="0/5 * * * * ? ") public void test2Task(){ DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); log.debug(Thread.currentThread() + " " + sdf.format(new Date())); }

}

2、分開配置

以下例子,若是隻有一個Bean,名字爲taskScheduler,或者方法名爲taskScheduler則會做爲自動的Scheduler。使用 @Scheduled即對應的是此TaskScheduler。

參見文章:  https://blog.csdn.net/sinianliushui/article/details/78841713

/**
 * description: 
 * 定時任務
 * @Autor:DennyZhao
 * @Date:2019/2/15
 * @Version: 1.0.0
 */
@Component
@EnableScheduling
public class SchedulerConfig {
    /** task相關的屬性文件 **/
    @Autowired
    private TaskProperties taskProperties;

    /**
     * 設備組織用Job
     * @return
     */
   @Bean("DeviceJob")
   public TaskScheduler initDeviceOrgTask(){
       ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
       //線程池大小
       scheduler.setPoolSize(taskProperties.getDeviceThreadCount());
       //線程名字前綴
       scheduler.setThreadNamePrefix("taskThread-deviceTask: ");
       scheduler.initialize();
       Trigger trigger = new CronTrigger(taskProperties.getDeviceOrgCron());
       scheduler.schedule(new DeviceOrgTask(), trigger);
       return scheduler;
   }

    /**
     * Jpush用Job
     * @return
     */
    @Bean("JpushJob")
    public TaskScheduler initJpushTask(){
        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
        //線程池大小
        scheduler.setPoolSize(taskProperties.getJpushThreadCount());
        //線程名字前綴
        scheduler.setThreadNamePrefix("taskThread-jpushTask: ");
        scheduler.initialize();
        Trigger trigger = new CronTrigger(taskProperties.getJpushReportCron());
        scheduler.schedule(new JpushReportTask(), trigger);
        return scheduler;
    }
}

TaskPropertis

/**
 * description: 
 * JPUSH執行任務相關參數
 *
 * @Autor:DennyZhao
 * @Date:2019/2/15
 * @Version: 1.0.0
 */
@Component
@PropertySource("classpath:task-config.properties")
@ConfigurationProperties(prefix="task")
@Data
public class TaskProperties {

    /** 極光推送appKey **/
    private String jpushAppKey;
    /** 極光推送secretKey **/
    private String jpushSecretKey;



    /** 設備JOB的線程數 **/
    private int deviceThreadCount;
    /** 設備組織Cron **/
    private String deviceOrgCron;
    /** Jpush的JOB線程數 **/
    private int jpushThreadCount;
    /** Jpush的推送報告Cron **/
    private String jpushReportCron;
}

建立類實現Runable接口便可使用。

@Component
@Slf4j
public class DeviceOrgTask implements Runnable {

    @Override
    public void run() {
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.debug(Thread.currentThread() + "  " + sdf.format(new Date()));
    }
}

 

問題: 

     1.  從以上的一簡易配置中(若是不添加SchedulerConfig)也能夠運行,發現若是在方法中添加Thread.sleep(),會影響下面方法的運行和下次的運行時間。

        由於默認的 ConcurrentTaskScheduler 計劃執行器採用Executors.newSingleThreadScheduledExecutor() 實現單線程的執行器。

        所以要使用異步: 採用異步的方式執行調度任務,配置 Spring 的 @EnableAsync,在執行定時任務的方法上標註 @Async配置任務執行。注意線程池大小要依據單個任務時間和任務間隔。

      2. 分佈式重複執行

           1.使用 redis分佈式鎖setnx命令 來控制是否已經存在有任務在執行。

            2.使用spring的shedLock,建立一個數據表,先更新者執行,非更新者不執行。

               參見:https://segmentfault.com/a/1190000011975027

      3. 主程序掛掉後,job中止,數據丟失

            使用redis記錄執行時間。

 異常:  

[ERROR] 2019-03-21 14:00:38,757 >>> org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler.handleError(TaskUtils.java:96)
[massage] Unexpected error occurred in scheduled task.
java.lang.IllegalStateException: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@8f84321 has been closed already

使用applicationContext未獲取到bean異常。

因EnabledTask會使得任務在執行完後closeContext致使,在配置文件添加:

spring.cloud.task.closecontext_enable=false

 

高版本用 spring.cloud.task.close_context_enabled=false

 

參考文章: https://stackoverflow.com/questions/48933575/spring-cloud-task-scheduling-context-closed

相關文章
相關標籤/搜索