欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring實現(xiàn)定時任務的幾種方式總結(jié)

 更新時間:2024年07月09日 11:57:33   作者:cold__liang  
Spring Task 是 Spring 框架提供的一種任務調(diào)度和異步處理的解決方案,可以按照約定的時間自動執(zhí)行某個代碼邏輯它可以幫助開發(fā)者在 Spring 應用中輕松地實現(xiàn)定時任務、異步任務等功能,提高應用的效率和可維護性,需要的朋友可以參考下本文

一.簡介

Spring Task 是 Spring 框架提供的一種任務調(diào)度和異步處理的解決方案??梢园凑占s定的時間自動執(zhí)行某個代碼邏輯它可以幫助開發(fā)者在 Spring 應用中輕松地實現(xiàn)定時任務、異步任務等功能,提高應用的效率和可維護性。

二.實現(xiàn)

一.基于注解@Scheduled

1.通過@Scheduled注釋結(jié)合cron表達式實現(xiàn)  cron表達式:

cron表達式是一種用于設(shè)置定時任務的語法規(guī)則。它由6個字段組成,分別表示秒、分、小  時、日期、月份和星期幾。每個字段都可以設(shè)置一個數(shù)字、一組數(shù)字(用逗號分隔)、一段數(shù)字范圍(用短橫線分隔)、通配符(表示任意值)或者特定的字符(如星期幾的英文縮寫)

 語法規(guī)則:

Cron表達式的詳細用法 - 簡書

示例:

0 0 0 * * ?:每天的零點整執(zhí)行任務。
0 0 */2 * * ?:每隔2小時執(zhí)行一次任務。
0 0 12 * * ?:每天中午12點執(zhí)行任務。
 
0 15 10 * * ?:每天上午10點15分執(zhí)行任務。
 
0 0 6,18 * * ?:每天的早上6點和晚上6點執(zhí)行任務。
 
0 0/30 8-18 * * ?:每天的上午8點到下午6點之間,每隔30分鐘執(zhí)行一次任務。
 
0 0 0 1 1 ?:每年的1月1日零點整執(zhí)行任務。
 
0 0 0 * * 2:每周的星期二零點整執(zhí)行任務。
0 0 0 ? * 6#3:每月的第三個星期六零點整執(zhí)行任務。
 
0 0 0 L * ?:每個月的最后一天零點整執(zhí)行任務。
 
————————————————

結(jié)合@Scheduled:

@Scheduled(cron ="*/6 * * * * ?") 
public void sayHello() { 
System.out.println("hello"); }

輸出結(jié)果:

注:啟動類需要能掃描到定時任務類,否則定時任務啟動不起來。

除了cron表達式外,還支持(感興趣可以進一步了解)

1.fixedRate:控制方法執(zhí)行的間隔時間,是以上一次方法執(zhí)行完開始算起,如上一次方法執(zhí)行阻塞住了,那么直到上一次執(zhí)行完,并間隔給定的時間后,執(zhí)行下一次。

2.initialDelay:initialDelay = 10000 表示在容器啟動后,延遲10秒后再執(zhí)行一次定時器。

   

優(yōu)缺點:

優(yōu):添加注解即可,使用方便。

缺:1.@Scheduled作用在方法上,方法不能有參數(shù)

 2.@Scheduled注解只能在開始就寫好,無法動態(tài)定義

3.spring支持的springtask的cron語句無法識別年份,也就是定時任務以固定頻率執(zhí)行,無法做到只執(zhí)行一次。

二.基于接口方式SchedulingConfigurer:

為了實現(xiàn)動態(tài)定義定時任務

一.創(chuàng)建數(shù)據(jù)庫表和相應字段存放cron語句

drop table if exists scheduled;
create table scheduled (
cron_id varchar(30) NOT NULL primary key,
cron_name varchar(30) NULL,
cron varchar(30) NOT NULL
);
insert into scheduled values ('1','定時器任務一','0/6 * * * * ?');

二.新增mapper類獲取數(shù)據(jù)庫存放的cron表達式    

@Select("select cron from cron_demo where cron_id=#{id}")
public String getCronById(int id);

三.新建task類執(zhí)行定時任務

public class TaskDemo implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask();//or: addCronTask...
    }
 
    private void process(){
        System.out.println("cron執(zhí)行");
    }//要執(zhí)行的邏輯
}

注意實現(xiàn)SchedulingConfigurer接口

用于添加定時任務的方法在這里很多很靈活,如addTriggerTask,addCronTask,并且方法重載也較多,建議查看源碼學習

這里介紹常用api:addTriggerTask,和addCronTask

addTriggerTask:

第一個方法實際是調(diào)用第二個方法

Runable task為要執(zhí)行的邏輯(想要定時實現(xiàn)的方法),Trigger trigger為使用某種方式封裝的cron語句,介紹一個簡單易懂好用的實現(xiàn)類---CronTrigger 

expression為cron表達式,zonid為代表時區(qū)(不用管,會調(diào)用系統(tǒng)默認時區(qū)),默認使用第一個構(gòu)造方法即可

第二種:

CronTask是TriggerTask的子類,其成員可謂非常人性化,expression即為cron表達式,構(gòu)造方法再傳入runable執(zhí)行內(nèi)容即可

示例:

public class TaskDemo implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addCronTask(this::process,cronMapper.getCronByid(1)))
    }//要執(zhí)行的邏輯
    private void process(){
        System.out.println("cron執(zhí)行");
    }
}

從上示例看出,當用addTriggetTask時,如果用Crontask,用法和addCronTask差不多,這兩個的底層都是調(diào)用了一個叫add的方法

擴展:Runnable runnabke的寫法

注:Runable是線程的知識點,由于本人目前沒有學習java線程部分,無法講解其底層原理,只介紹在實現(xiàn)定時任務時的用法

Runable只是一個接口,內(nèi)部只有一個void的run方法

需要定義實現(xiàn)類,如下在納新大作業(yè)中的實現(xiàn):

private class TaskRunnable implements Runnable{
    private final Cron cron;
 
    public TaskRunnable(Cron cron) {
        this.cron = cron;
    }
 
    @Override
    public void run() {
        //定義任務要做的事,即把visibility字段設(shè)為0表示可見,
        // 同時把時間設(shè)為設(shè)定的發(fā)送時間
        // (如果設(shè)為當前時間由于定時任務管理器CronManageTask掃面時間間隔問題會導致實際執(zhí)行時間與預期發(fā)送時間不一致)
        mailboxService.lambdaUpdate()
                .set(Email::getVisibility,(short)0)
                .set(Email::getSendTime,cron.getExecuteTime())
                .eq(Email::getId,cron.getEmailId())
                .update();
 
    }
}

這里的cron為從外傳入的參數(shù),可以通過構(gòu)造方法將cron傳入對象中,這就解決了@Secheduled無法傳遞參數(shù)的問題,

示例:

@RequiredArgsConstructor
public class TaskDemo implements SchedulingConfigurer {
    private final CronMapper cronMapper;
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        Runnable task =this::process;
        CronTask cronTask = new CronTask(task,cronMapper.getCronById(1));
        taskRegistrar.addTriggerTask(cronTask);
      
    }
 
    private void process(){
        System.out.println("cron執(zhí)行");
    }//要執(zhí)行的邏輯
    
} 

還有一個在查找博客時看到的示例,方法基本上一樣只不過使用了lambda表達式,但是匿名內(nèi)部類我只了解一點點,還請大佬help:

@Autowired
protected CronMapper cronMapper;
 
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
    scheduledTaskRegistrar.addTriggerTask(() -> process(),
            triggerContext -> {
                String cron = cronMapper.getCron(1);
                if (cron.isEmpty()) {
                    System.out.println("cron is null");
                }
                return new CronTrigger(cron).nextExecutionTime(triggerContext);
            });
}
 
private void process() {
    System.out.println("基于接口定時任務");
}

三.基于ThreadPoolTaskScheduler輕量級多線程定時任務框架

上述基于接口的方法解決了基于注解無法實現(xiàn)的動態(tài)定義cron表達式和方法傳入?yún)?shù)的問題,但示例無法實現(xiàn)根據(jù)傳入的年份指定在某一年特定日期執(zhí)行定時任務,下面介紹一種實現(xiàn)方式

一.簡介:

springboot中有一個bean,ThreadPoolTaskScheduler,可以很方便的對重復執(zhí)行的任務進行調(diào)度管理;相比于通過java自帶的周期性任務線程池

ScheduleThreadPoolExecutor,此bean對象支持根據(jù)cron表達式創(chuàng)建周期性任務。

當然,ThreadPoolTaskScheduler其實底層使用也是java自帶的線程池。

二.常用api介紹

ThreadPoolTaskScheduler 內(nèi)部方法非常豐富,本文實現(xiàn)的是一種corn表達式,周期執(zhí)行

  • schedule(Runnable task, Trigger trigger) corn表達式,周期執(zhí)行
  • schedule(Runnable task, Date startTime) 定時執(zhí)行
  • scheduleAtFixedRate(Runnable task, Date startTime, long period) 定時周期間隔時間執(zhí)行。間隔時間單位 TimeUnit.MILLISECONDS

scheduleAtFixedRate(Runnable task, long period) 間隔時間執(zhí)行。單位毫秒

三.上實戰(zhàn) 

1.新建實現(xiàn)類cron(隨便取的名)這里直接使用lambda注解

 @Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("thread_cron")
public class cron {
    private String title;
    private LocalDate startTime;//起始時間
    private LocalDate deadTime;//結(jié)束時間
    private LocalDateTime executeTime;//運行時間
}

解釋:startTime為任務啟動年份第一天,deadTime為任務啟動年份最后一天(指定年份執(zhí)行,也可以根據(jù)需求調(diào)整),executeTime為任務執(zhí)行時間

2.創(chuàng)建對應的service接口和實現(xiàn)類

public interface ThreadService extends IService<Cron> {
    void startCron(Cron cron);//啟動定時任務
    void stopCron(Cron cron);//停止定時任務
    void changeCron(Cron cron);//更新定時任務
}

實現(xiàn)類的具體邏輯:

1.每個任務有一個執(zhí)行期限,就是cron類中的startTime和deadTime,這里一般存儲年份信息,將任務限定在某年執(zhí)行,在啟動定時任務也就是調(diào)用startCron方法時,需要判斷當前時間是否在期限內(nèi)

2.同一任務可能被多次啟動,這顯然是多余的,因此需要將已經(jīng)啟動過的定時任務放入一個集合中,在調(diào)用startCron時檢查當前任務是否在集合中。執(zhí)行定時任務的方法是ThreadPoolTaskScheduler中的public ScheduledFuture schedule(Runnable task, Trigger trigger)這個方法,可以看到,方法參數(shù)在上面基于接口處講過,方法返回值ScheduledFuture包含執(zhí)行的任務的詳細信息,停止任務也需要調(diào)用其中的boolean cancel(boolean mayInterruptIfRunning)方法,因此,可以用此類型的集合來存放執(zhí)行中的定時任務

示例:

準備:

private final ThreadPoolTaskScheduler threadPoolTaskScheduler;
private final Map<Integer, ScheduledFuture<?>> futureMap = new HashMap<>();
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
    return new ThreadPoolTaskScheduler();
}

startCron:

public void startCron(Cron cron) {
    //1.判斷cron是否被執(zhí)行過
    if(futureMap.containsKey(cron.getId())){log.info("定時任務存在 id={}",cron.getId());return;}
    //2.判斷是否還沒過執(zhí)行時間
    //在springTask中,cron表達式無法對年進行定時,故使用startTime和deadTime來限制定時任務要執(zhí)行的年份
    if(LocalDate.now().isEqual(cron.getStartTime()) || LocalDate.now().isEqual(cron.getDeadTime()) ||
            (LocalDate.now().isAfter(cron.getStartTime()) && LocalDate.now().isBefore(cron.getDeadTime()))){
        //提取執(zhí)行時間
        LocalDateTime executeTime = cron.getExecuteTime();
        //組裝cron表達式
        DateTimeFormatter cronFormatter = DateTimeFormatter.ofPattern("s m H d M");
        String cronExp = cronFormatter.format(executeTime)+" ?";
        //執(zhí)行scheduled任務
        ScheduledFuture<?> future = threadPoolTaskScheduler.schedule(new TaskRunnable(cron), new CronTrigger(cronExp));
        //將future傳入futureMap集合表示任務啟動,避免任務重復啟動
        futureMap.put(cron.getId(),future);
        //輸出日志
        log.info("任務啟動,id:{},executeTime:{}",cron.getId(),cron.getExecuteTime());
    }
}

stopCron:

 
public void stopCron(Cron cron) {
    ScheduledFuture<?> future = futureMap.get(cron.getId());
    if (future != null) {
        future.cancel(true);
        futureMap.remove(cron.getId());
        log.info("任務停止,id:{}",cron.getId());
    }
}

changeCron:

public void changeCron(Cron cron) {
    startCron(cron);
    stopCron(cron);
}

TaskRunnable類:

private class TaskRunnable implements Runnable{
    private final Cron cron;
    public TaskRunnable(Cron cron) {
        this.cron = cron;
    }
    @Override
    public void run() {
        //定義任務要做的事
        System.out.println("定時任務執(zhí)行,id:"+cron.getId());
    }
}

3.創(chuàng)建cronTaskManager類

注:cronTaskManager類上加注解@Compoment

上述解決了基于注解的三個問題,但是還存在一個問題,定時任務制定后被啟用需要保持服務器或應用程序一直被啟動,如果關(guān)閉應用程序,定時任務也將失效,因此需要一個類來管理定時任務,基本思路是:在應用啟動時每隔一段時間掃描一邊數(shù)據(jù)庫存放的定時任務,將其啟動或停止。

public class cronTaskManager {
    @Lazy
    private final ThreadService threadService;
    //每半個小時掃描一次
    @Scheduled(cron = "0 0/30 * * * ?")
    public void cronManage() {
        log.info("定時任務啟動");
        List<Cron> list = threadService.list();
        list.forEach(cron -> {
            if (LocalDate.now().isAfter(cron.getDeadTime())) {
                threadService.stopCron(cron);
                threadService.removeById(cron.getId());
                log.info("任務過期刪除,id:{},executeTime:{}",cron.getId(),cron.getExecuteTime());
            } else {
                log.info("嘗試啟動任務,id:{},executeTime:{}",cron.getId(),cron.getExecuteTime());
                threadService.startCron(cron);
            }
        });
    }
}

啟動應用定時啟動ronManager方法掃描數(shù)據(jù)庫存在的定時任務,如果任務過期則刪除,否則嘗試啟動。

以上就是Spring實現(xiàn)定時任務的幾種方式總結(jié)的詳細內(nèi)容,更多關(guān)于Spring實現(xiàn)定時任務的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java設(shè)計模式之工廠模式

    Java設(shè)計模式之工廠模式

    這篇文章主要為大家詳細介紹了Java設(shè)計模式之工廠模式,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • springmvc處理模型數(shù)據(jù)ModelAndView過程詳解

    springmvc處理模型數(shù)據(jù)ModelAndView過程詳解

    這篇文章主要介紹了springmvc處理模型數(shù)據(jù)ModelAndView過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-01-01
  • Springboot詳解整合SpringSecurity實現(xiàn)全過程

    Springboot詳解整合SpringSecurity實現(xiàn)全過程

    Spring Security基于Spring開發(fā),項目中如果使用Springboot作為基礎(chǔ),配合Spring Security做權(quán)限更加方便,而Shiro需要和Spring進行整合開發(fā)。因此作為spring全家桶中的Spring Security在java領(lǐng)域很常用
    2022-07-07
  • Springboot?如何使用BindingResult校驗參數(shù)

    Springboot?如何使用BindingResult校驗參數(shù)

    這篇文章主要介紹了Springboot?如何使用BindingResult校驗參數(shù),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • Java中保證線程順序執(zhí)行的操作代碼

    Java中保證線程順序執(zhí)行的操作代碼

    本文給大家分享一篇教程關(guān)于java線程順序執(zhí)行問題,如何保證線程的順序執(zhí)行呢?今天通過實例代碼給大家詳細講解下,感興趣的朋友跟隨小編一起看看吧
    2021-05-05
  • Maven中jar包下載失敗的幾種解決方法

    Maven中jar包下載失敗的幾種解決方法

    本文主要介紹了Maven中jar包下載失敗的幾種解決方法,包括配置國內(nèi)Maven源、刪除本地jar包目錄重新下載,具有一定的參考價值,感興趣的可以了解一下
    2025-02-02
  • Spring Mybatis Mapper模糊查詢的幾種方法

    Spring Mybatis Mapper模糊查詢的幾種方法

    在Spring結(jié)合Mybatis進行開發(fā)時,實現(xiàn)模糊查詢是一個常見需求,在Mybatis中,LIKE查詢可以通過多種方式實現(xiàn),本文給大家介紹了Spring Mybatis Mapper模糊查詢的幾種方法,需要的朋友可以參考下
    2024-03-03
  • Java SpringMVC異步處理詳解

    Java SpringMVC異步處理詳解

    這篇文章主要介紹了Java springmvc的處理異步,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2021-10-10
  • Spring Boot Admin Server管理客戶端過程詳解

    Spring Boot Admin Server管理客戶端過程詳解

    這篇文章主要介紹了Spring Boot Admin Server管理客戶端過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • SpringBoot面試突擊之過濾器和攔截器區(qū)別詳解

    SpringBoot面試突擊之過濾器和攔截器區(qū)別詳解

    過濾器(Filter)和攔截器(Interceptor)都是基于?AOP(Aspect?Oriented?Programming,面向切面編程)思想實現(xiàn)的,用來解決項目中某一類問題的兩種“工具”,但二者有著明顯的差距,接下來我們一起來看
    2022-10-10

最新評論