@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 启动定时任务
结果如下