前言
@Scheduled适用与监听任务较少的,而Quartz适合较多的,为确保可伸缩性,Quartz采用了基于多线程的架构。启动时,框架初始化一套worker线程,这套线程被调度器用来执行预定的作业。这就是Quartz怎样能并发运行多个作业的原理。Quartz依赖一套松耦合的线程池管理部件来管理线程环境。
实现定时器的方式有两种:
- Scheduled:spring 3.0 后自带的定时器
 - Quartz:第三放定时器框架
 
1.Scheduled
1.1创建任务类
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.scheduling.annotation.Async;
import java.util.Date;
@Component
public class Schedule {
    @Async
    @Scheduled(fixedRate = 2000)
    public void task() {
        System.out.println("启动定时任务:" + new Date());
    }
}使用 @Scheduled 定义任务执行时间,代码中表示每隔 2 秒执行一次任务。
1.2启动定时任务
在启动类上添加@EnableScheduling
测试结果:

2.Quartz
2.1导入依赖
        <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>2.2创建定时任务类
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
public class MyJob implements Job {
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("========quartz 测试=========="+new Date());
    }
}2.3创建配置类
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;
@Configuration
public class QuartzConfiguration {
    /**
     *  Job 工厂
     * @return
     */
    @Bean
    public JobDetailFactoryBean jobDetailFactoryBean() {
        JobDetailFactoryBean factory = new JobDetailFactoryBean();
        factory.setJobClass(MyJob.class);
        return factory;
    }
    /**
     *  Trigger 工厂
     * @return
     */
    @Bean
    public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactory) {
        SimpleTriggerFactoryBean factory = new SimpleTriggerFactoryBean();
        factory.setJobDetail(jobDetailFactory.getObject());
        // 执行间隔时间
        factory.setRepeatInterval(5000);
        // 重复执行次数
        factory.setRepeatCount(3);
        return factory;
    }
    /**
     *  Trigger 工厂
     * @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;
    }
}同样地,需要在 Spring Boot 的启动类上添加 @EnableScheduling 后,启动项目即可。
测试结果:

2.4依赖注入问题
实际开发中,任务类需要注入业务组件来执行定时任务,如下:
public class MyJob implements Job {
    @Autowired
    private UserDao userDao;
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        //添加
        User user1 = new User();
        user1.setuName("李四");
        int i = userDao.insertUser(user1);
        System.out.println(i);
        //查询
        User user = userDao.getUserById(1);
        System.out.println(user);
    }
}但是MyJob 生命周期并没有被 Spring 容器管理,因此无法注入 UserService,当定时器执行任务时会报空指针异常。

解决方案:
自定义任务工厂,重写创建任务实例的方法:
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;
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object object = super.createJobInstance(bundle);
        // 将任务实例纳入 Spring 容器中
        this.autowireCapableBeanFactory.autowireBean(object);
        return object;
    }
}修改QuartzConfiguration类 的 Scheduler 实现:
原:
@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;
}测试结果:


                
            
        
            
评论 (0)