亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

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

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

一.簡(jiǎn)介

Spring Task 是 Spring 框架提供的一種任務(wù)調(diào)度和異步處理的解決方案。可以按照約定的時(shí)間自動(dòng)執(zhí)行某個(gè)代碼邏輯它可以幫助開(kāi)發(fā)者在 Spring 應(yīng)用中輕松地實(shí)現(xiàn)定時(shí)任務(wù)、異步任務(wù)等功能,提高應(yīng)用的效率和可維護(hù)性。

二.實(shí)現(xiàn)

一.基于注解@Scheduled

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

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

 語(yǔ)法規(guī)則:

Cron表達(dá)式的詳細(xì)用法 - 簡(jiǎn)書(shū)

示例:

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

結(jié)合@Scheduled:

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

輸出結(jié)果:

注:?jiǎn)?dòng)類(lèi)需要能掃描到定時(shí)任務(wù)類(lèi),否則定時(shí)任務(wù)啟動(dòng)不起來(lái)。

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

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

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

   

優(yōu)缺點(diǎn):

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

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

 2.@Scheduled注解只能在開(kāi)始就寫(xiě)好,無(wú)法動(dòng)態(tài)定義

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

二.基于接口方式SchedulingConfigurer:

為了實(shí)現(xiàn)動(dòng)態(tài)定義定時(shí)任務(wù)

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

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','定時(shí)器任務(wù)一','0/6 * * * * ?');

二.新增mapper類(lèi)獲取數(shù)據(jù)庫(kù)存放的cron表達(dá)式    

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

三.新建task類(lèi)執(zhí)行定時(shí)任務(wù)

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

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

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

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

addTriggerTask:

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

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

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

第二種:

CronTask是TriggerTask的子類(lèi),其成員可謂非常人性化,expression即為cron表達(dá)式,構(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í)行");
    }
}

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

擴(kuò)展:Runnable runnabke的寫(xiě)法

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

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

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

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

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

示例:

@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í)行的邏輯
    
} 

還有一個(gè)在查找博客時(shí)看到的示例,方法基本上一樣只不過(guò)使用了lambda表達(dá)式,但是匿名內(nèi)部類(lèi)我只了解一點(diǎn)點(diǎn),還請(qǐng)大佬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("基于接口定時(shí)任務(wù)");
}

三.基于ThreadPoolTaskScheduler輕量級(jí)多線(xiàn)程定時(shí)任務(wù)框架

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

一.簡(jiǎn)介:

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

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

當(dāng)然,ThreadPoolTaskScheduler其實(shí)底層使用也是java自帶的線(xiàn)程池。

二.常用api介紹

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

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

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

三.上實(shí)戰(zhàn) 

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

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

解釋?zhuān)簊tartTime為任務(wù)啟動(dòng)年份第一天,deadTime為任務(wù)啟動(dòng)年份最后一天(指定年份執(zhí)行,也可以根據(jù)需求調(diào)整),executeTime為任務(wù)執(zhí)行時(shí)間

2.創(chuàng)建對(duì)應(yīng)的service接口和實(shí)現(xiàn)類(lèi)

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

實(shí)現(xiàn)類(lèi)的具體邏輯:

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

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

示例:

準(zhǔn)備:

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

changeCron:

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

TaskRunnable類(lèi):

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

3.創(chuàng)建cronTaskManager類(lèi)

注:cronTaskManager類(lèi)上加注解@Compoment

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

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

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

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

相關(guān)文章

  • Java設(shè)計(jì)模式之工廠(chǎng)模式

    Java設(shè)計(jì)模式之工廠(chǎng)模式

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

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

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

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

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

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

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

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

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

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

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

    Spring Mybatis Mapper模糊查詢(xún)的幾種方法

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

    Java SpringMVC異步處理詳解

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

    Spring Boot Admin Server管理客戶(hù)端過(guò)程詳解

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

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

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

最新評(píng)論