1. 程式人生 > >Spring Boot整合之定時任務

Spring Boot整合之定時任務

@Scheduled適用與監聽任務較少的,而Quartz適合較多的,為確保可伸縮性,Quartz採用了基於多執行緒的架構。啟動時,框架初始化一套worker執行緒,這套執行緒被排程器用來執行預定的作業。這就是Quartz怎樣能併發執行多個作業的原理。Quartz依賴一套鬆耦合的執行緒池管理部件來管理執行緒環境。

定時器:

1.Scheduled:spring 3.0 後自帶的定時器
2.Quartz:第三放定時器框架

 

1.Scheduled

1.1 建立任務類

package com.wyp.util;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;

/**
 * Scheduled定時器
 */
@Component
public class Schedule {

    @Scheduled(fixedRate = 2000)
    public void task() {
        System.out.println("啟動定時任務:" + new Date());
    }

}

使用@Scheduled 定義任務執行時間,程式碼中表示每隔2秒執行一次任務

1.2啟動定時任務

在啟動類上新增@EnableScheduling,如下:

package com.wyp;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@EnableScheduling
@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootApplication.class, args);
    }
}

啟動,到控制檯看結果。

 

2.Quartz

2.1匯入依賴

<!--匯入Quartz依賴-->
<dependency>
   <groupId>org.quartz-scheduler</groupId>
   <artifactId>quartz</artifactId>
   <version>2.2.1</version>
</dependency>
<dependency>
   <groupId>org.quartz-scheduler</groupId>
   <artifactId>quartz-jobs</artifactId>
   <version>2.2.1</version>
</dependency>
<!--匯入Quartz依賴-->

2.2 建立定時任務類

package com.wyp.util;

import com.wyp.dao.TTestDao;
import com.wyp.pojo.TTest;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;

public class MyJob implements Job {

    @Autowired
    private TTestDao tTestDao;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("========quartz 測試=========="+new Date());
        
    }
}

2.3 建立配置類

package com.wyp.util;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;

/**
 * Quartz定時配置類
 */
@Configuration
public class QuartzConfiguration {

    /**
     * Job 工廠
     * @return
     */
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean(){
        JobDetailFactoryBean factory = new JobDetailFactoryBean();
        factory.setJobClass(MyJob.class);
        return factory;
    }

    /**
     * Trigger 工廠
     * @param jobDetailFactory
     * @return
     */
    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactory){
        SimpleTriggerFactoryBean factory = new SimpleTriggerFactoryBean();
        //執行間隔時間
        factory.setRepeatInterval(5000);
        //重複執行次數
        factory.setRepeatCount(3);
        return factory;
    }

    /**
     * Trigger 工廠
     * @param jobDetailFactory
     * @return
     */
    @Bean
    public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactory){
        CronTriggerFactoryBean factory = new CronTriggerFactoryBean();
        factory.setJobDetail(jobDetailFactory.getObject());
        factory.setCronExpression("0/5 * * * * ?");
        return factory;
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactory){
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setTriggers(cronTriggerFactory.getObject());
        return factory;
    }

}

在啟動類上新增@EnableScheduling

2.4 依賴注入問題

package com.wyp.util;

import com.wyp.dao.TTestDao;
import com.wyp.pojo.TTest;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;

public class MyJob implements Job {

    @Autowired
    private TTestDao tTestDao;

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//        System.out.println("========quartz 測試=========="+new Date());
        TTest tTestListById = tTestDao.getTTestListById(2);
        System.out.println(tTestListById);
    }
}

但是MyJob 生命週期並沒有被 Spring 容器管理,因此無法注入 UserService,當定時器執行任務時會報空指標異常。

解決辦法:

自定義任務工廠,重寫建立任務例項的方法:

package com.wyp.util;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component("CustomAdaptableJobFactory")
public class CustomAdaptableJobFactory extends AdaptableJobFactory {

    @Autowired
    private AutowireCapableBeanFactory autowireCapableBeanFactory;

    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception{
        Object object = super.createJobInstance(bundle);
        //將任務例項納入 Spring 容器中
        this.autowireCapableBeanFactory.autowireBean(object);
        return object;
    }

}

修改QuartzConfiguration類:

原:

@Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactory){
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setTriggers(cronTriggerFactory.getObject());
        return factory;
    }

現:

@Bean
    public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactory,CustomAdaptableJobFactory customAdaptableJobFactory){
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setTriggers(cronTriggerFactory.getObject());
        factory.setJobFactory(customAdaptableJobFactory);
        return factory;
    }

2.5 啟動定時任務

結果如下