Job中无法注入Bean

环境

  • SpringBoot 2.6.4
  • Quartz 2.3.2

现象

在JOB对象中,使用@Autowire注解注入spring的bean对象,抛出空指针异常;

源码分析

scheduler使用SchedulerFactoryBean对象获取,获取方式是

Scheduler scheduler = schedulerFactoryBean.getScheduler();

因为springBoot集成了spring-boot-starter-quartz,因此可以在QuartzAutoConfiguration配置类中找到SchedulerFactoryBean的定义,如下所示:


@Bean
@ConditionalOnMissingBean
public SchedulerFactoryBean quartzScheduler(QuartzProperties properties,
		ObjectProvider<SchedulerFactoryBeanCustomizer> customizers, ObjectProvider<JobDetail> jobDetails,
		Map<String, Calendar> calendars, ObjectProvider<Trigger> triggers, ApplicationContext applicationContext) {
	SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
	SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();
	jobFactory.setApplicationContext(applicationContext);
	schedulerFactoryBean.setJobFactory(jobFactory);
	//省略其他代码
	return schedulerFactoryBean;
}

通过上述代码可以看到SchedulerFactoryBean设置类工厂类SpringBeanJobFactory,进入该类可以看到该类继承了AdaptableJobFactory类,并且实现了ApplicationContextAware接口,查看该类的创建job实例的方法,如下所示:

protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
	Object job = this.applicationContext != null ? this.applicationContext.getAutowireCapableBeanFactory().createBean(bundle.getJobDetail().getJobClass(), 3, false) : super.createJobInstance(bundle);
	if (this.isEligibleForPropertyPopulation(job)) {
		//省略其他代码
	}
	return job;
}

该方法中通过applicationContext获取到AutoWireCapableBeanFactory,进而去创建bean,也即将创建的JOB对象同时注入到spring容器中,那么也就是说在该版本的springboort中,默认情况下在JOB中注入bean是可以实现的。

不能注入原因

按照上面的分析,默认情况下,在job中注入bean是可以正常使用的,那么为什么还是出现了NullPonterException呢?原因在于项目中因为要设置Quarz的数据源,重新定义了SchedulerFactoryBean,原始代码如下:

@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
	SchedulerFactoryBean factory = new SchedulerFactoryBean();
	factory.setDataSource(dataSource);
	return factory;
}

这就覆盖了QuartzAutoConfiguration配置中的原始定义,此时的JOB是没有交给spring容器管理的,也就导致了注入其他bean时会出现空指针;

解决方案

在重写的配置类中,添加SpringBeanJobFactory对象,如下所示:

@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
	SchedulerFactoryBean factory = new SchedulerFactoryBean();
	factory.setDataSource(dataSource);
    //关键代码
	SpringBeanJobFactory jobFactory = new SpringBeanJobFactory();
	jobFactory.setApplicationContext(applicationContext);
	factory.setJobFactory(jobFactory);
    //关键代码
	return factory;
}
posted @ 2022-05-23 11:50  一步一年  阅读(196)  评论(0编辑  收藏  举报