写项目的时候,在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

  1. package com.clevesheep.quartz.config;
  2. import lombok.RequiredArgsConstructor;
  3. import org.quartz.spi.TriggerFiredBundle;
  4. import org.springframework.beans.factory.annotation.Autowired;
  5. import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.scheduling.quartz.SpringBeanJobFactory;
  8. /**
  9. * Created By Intellij IDEA
  10. *
  11. * @author Xinrui Yu
  12. * @date 2022/5/3 20:48 星期二
  13. */
  14. @Configuration
  15. @RequiredArgsConstructor
  16. public class CustomJobFactory extends SpringBeanJobFactory {
  17. private final AutowireCapableBeanFactory capableBeanFactory;
  18. @Override
  19. protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
  20. Object jobInstance = super.createJobInstance(bundle);
  21. capableBeanFactory.autowireBean(jobInstance);
  22. return jobInstance;
  23. }
  24. }

SchedulerConfig.java部分代码

  1. private final CustomJobFactory customJobFactory;
  2. private final DataSource dataSource;
  3. @Bean
  4. public Scheduler scheduler() throws IOException, SchedulerException {
  5. Scheduler scheduler = schedulerFactoryBean().getObject();
  6. assert scheduler != null;
  7. scheduler.setJobFactory(customJobFactory);
  8. return scheduler;
  9. }
  10. @Bean
  11. public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
  12. SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
  13. factoryBean.setSchedulerName("cluster1");
  14. factoryBean.setDataSource(dataSource);
  15. factoryBean.setApplicationContextSchedulerContextKey("application");
  16. factoryBean.setQuartzProperties(quartzProperties());
  17. factoryBean.setTaskExecutor(schedulerThreadPool());
  18. return factoryBean;
  19. }

之后,就可以直接在我们的自定义Job中注入Bean了
image.png

另外:如果使用的是JPA ORM框架,那么在进行数据库操作的时候,一定要在对应的方法上加上事务注解,也就是@Transactional,否则会报No Session的异常。