文章目录
定时任务
schedule定时任务
spring提供的定时任务器,
@Component
public class Schedule {
@Scheduled(cron = "0/2 * * * * ?")
public void test(){
System.out.println("springboot定时任务:"+ new Date());
}
}
@SpringBootApplication
@EnableJms
@EnableScheduling
public class DiancanApplication {
public static void main(String[] args) {
SpringApplication.run(DiancanApplication.class, args);
}
}
spring schedule是基于java提供的ScheduledExecutorService中的schedule(Runnable command, long delay, TimeUnit unit)来实现的
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
scheduledExecutorService.scheduleAtFixedRate(()->{
System.out.println("----------定时任务AAAAAAAAAAAAAAA-----------" + new Date());
},0,5, TimeUnit.SECONDS);
}
ScheduledExecutorService实现任务调度的主要是通过其延时队列,延时队列内部是一个堆的实现,其实就是最小堆,每个进入队列的任务会通过执行时间进行排序,时间相同则先提交的先执行
执行原理:
- 线程从延时队列中获取该执行的任务,执行完后将执行时间修改为下一次的执行时间在放回队列中
cron表达式:
我对cron表达式具有的了解呢,他的语法应该是从左到右是,他有两种表达形式,7个字段和6个字段的区别是最后的year
second min hour day month week year
但是在开发过程中选择去网上找在线的cron转换来生成我需要用到的cron表达式
quartz
主要组件:
- Job任务类
- 实现Job接口,重写execute方法实现定时任务逻辑
- 触发器
- 绑定任务
- 编写cron表达式
- 调度器
- 绑定任务和触发器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
编写Job
public class MyJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("quartz定时任务:"+new Date());
}
}
编写触发器和调度器,并且绑定任务
@Configuration
public class QuartzConfig {
@Bean(value = "myJobDetail")
public JobDetailFactoryBean myJobDetail() {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(MyJob.class);
factoryBean.setGroup("group1");
factoryBean.setName("MyJob");
return factoryBean;
}
@Bean
public CronTriggerFactoryBean myJobTriggrt(@Qualifier("myJobDetail") JobDetail jobDetail){
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
factoryBean.setJobDetail(jobDetail);
factoryBean.setStartDelay(1000L);
factoryBean.setName("trigger1");
factoryBean.setGroup("group1");
factoryBean.setCronExpression("0/2 * * * * ? ");
return factoryBean;
}
//调度工厂
@Bean
public SchedulerFactoryBean schedulerFactory1Bean(@Qualifier("myJobTriggrt") Trigger simpleJobTrigger)
throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setTriggers(simpleJobTrigger);
return factory;
}
}
但是
这里有个问题需要注意:上文提到的job类的实现主要是打印的逻辑,即没有用到其他业务类去完成一些业务,实际开发中的时候,我们往往需要用到定时任务去完成一些业务,那就必然会引出一个问题,如果在job中注入业务对象会有问题吗
@Component
public class MyJob implements Job {
@Autowired
private TestService testService;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
testService.A();
}
}
配置类不变直接运行,结果如下所示:
报的是空指针异常,证明我们的testService没有成功注入进来,那为什么没有成功注入呢?
我们再看配置类
@Bean(value = "myJobDetail")
public JobDetailFactoryBean myJobDetail() {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(MyJob.class);
factoryBean.setGroup("group1");
factoryBean.setName("MyJob");
return factoryBean;
}
可以知道Job的实例化是交由JobDetailFactoryBean去做的,那么他底层其实是通过AdaptableJobFactory的下面这个方法完成job的实例化
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Class<?> jobClass = bundle.getJobDetail().getJobClass();
return ReflectionUtils.accessibleConstructor(jobClass).newInstance();
}
可以看到,他底层实例化的方式就是通过getclass然后通过反射的newInstance方法完成实例化
所以,Job对象的实例化是不依靠spring IOC容器取做的,即spring IOC容器中没有这个job对象,所以,spring IOC容器管理的业务类肯定也无法在Job中完成注入,因为spring的要求是注入的对象和被注入的对象都要在IOC容器中,这样才能完成对象的注入
所以,问题的解决方案也出来,就是就是将AdaptableJobFactory创建的Job对象手动的添加到spring ioc容器中
@Configuration
public class MyAdaptableJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object job = super.createJobInstance(bundle);
//将创建出来的job手动添加到IOC容器中
autowireCapableBeanFactory.autowireBean(job);
return job;
}
}
这样还不行,使用的还是默认的JobDetailFactoryBean。我们需要修改下使用我们新写的MyAdaptableJobFactory,在配置类的调度器中设置下即可
@Autowired
private MyAdaptableJobFactory myAdaptableJobFactory;
//调度工厂
@Bean
public SchedulerFactoryBean schedulerFactory1Bean(@Qualifier("myJobTriggrt") Trigger simpleJobTrigger)
throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//使用我们的myAdaptableJobFactory
factory.setJobFactory(myAdaptableJobFactory);
factory.setTriggers(simpleJobTrigger);
return factory;
}
就此,任务成功执行: