写项目的时候,在Quartz的自定义Job中注入Spring的Bean的时候,一直报空指针异常。
经过调试发现,确定为注入的Bean为Null
本文记录一下如果排除这种问题
Bean注入为Null
所谓Bean注入,就是让Spring的IOC容器,来帮我们去创建某个类的实例,从而避免我们手动的去new对象。
那么,什么情况下我们注入的Bean会为Null
比较常见的一种情况就是:我们某个类中有使用Bean注入的属性,但是如果我们手动的New这个类的对象,那么使用Bean注入的属性就会出现Null的情况
如何解决这种情况?
将这个类同样交由Spring的IOC容器进行管理(在这个类上使用@Component,@Controller等注解),然后在需要创建这个类的对象的时候,同样采用Bean注入的方式进行创建。
Quartz中为什么会出现这种异常?
原因: 在Quartz中,定时任务的Job对象实例化是通过Quartz内部自己完成的(也就是说内部手动new出来的),并没有交由Spring的IOC容器进行管理,那么结合上文所述,就能解释为什么注入的属性会为null
Quartz内部没有办法感知到Spring容器所管理的Bean,所以无法在创建Job的时候将Bean给装配进来,这是一种运行时异常
解决: 通过自定义JobFactory,将创建好的Job交给Spring进行管理
CustomJobFactory.java
package com.clevesheep.quartz.config;import lombok.RequiredArgsConstructor;import org.quartz.spi.TriggerFiredBundle;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.config.AutowireCapableBeanFactory;import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.quartz.SpringBeanJobFactory;/*** Created By Intellij IDEA** @author Xinrui Yu* @date 2022/5/3 20:48 星期二*/@Configuration@RequiredArgsConstructorpublic class CustomJobFactory extends SpringBeanJobFactory {private final AutowireCapableBeanFactory capableBeanFactory;@Overrideprotected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {Object jobInstance = super.createJobInstance(bundle);capableBeanFactory.autowireBean(jobInstance);return jobInstance;}}
SchedulerConfig.java部分代码
private final CustomJobFactory customJobFactory;private final DataSource dataSource;@Beanpublic Scheduler scheduler() throws IOException, SchedulerException {Scheduler scheduler = schedulerFactoryBean().getObject();assert scheduler != null;scheduler.setJobFactory(customJobFactory);return scheduler;}@Beanpublic SchedulerFactoryBean schedulerFactoryBean() throws IOException {SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();factoryBean.setSchedulerName("cluster1");factoryBean.setDataSource(dataSource);factoryBean.setApplicationContextSchedulerContextKey("application");factoryBean.setQuartzProperties(quartzProperties());factoryBean.setTaskExecutor(schedulerThreadPool());return factoryBean;}
之后,就可以直接在我们的自定义Job中注入Bean了
另外:如果使用的是JPA ORM框架,那么在进行数据库操作的时候,一定要在对应的方法上加上事务注解,也就是
@Transactional,否则会报No Session的异常。
