写项目的时候,在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
@RequiredArgsConstructor
public class CustomJobFactory extends SpringBeanJobFactory {
private final AutowireCapableBeanFactory capableBeanFactory;
@Override
protected 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;
@Bean
public Scheduler scheduler() throws IOException, SchedulerException {
Scheduler scheduler = schedulerFactoryBean().getObject();
assert scheduler != null;
scheduler.setJobFactory(customJobFactory);
return scheduler;
}
@Bean
public 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的异常。