一、问题描述
SpringBoot 整合 Quartz 进行定时任务开发时,job 中注入业务 Service,使用 @Autowired 注解获取对象为 null ,执行时报空指针异常
二、分析
Spring 容器可以管理 Bean,但是 Quartz 的 job 是自己管理的,job 无法被容器识别,即使在自定义的 job 上面加上@Component 注解,依然无效,原因是 job 对象在 spring 容器加载的时候,能够注入 bean,但是在调度时,job 对象会重新创建,此时就导致了已经注入的对象丢失,因此报空指针异常。
三、解决办法
3.1 采用自定义静态工具类的方式,创建 AppContextUtil 类,实现 ApplicationContextAware 接口,此工具类会在 spring 容器启动后,自动加载,使用其提供的 Bean 方法获取想要的 bean 即可,代码如下:
import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;
@Component @Slf4j public class AppContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { AppContextUtil.applicationContext = applicationContext; log.info("==================ApplicationContext加载-----------------"); }
public static ApplicationContext getApplicationContext(){ return applicationContext; }
public static Object getBean(String name){ return applicationContext.getBean(name); }
public static <T> T getBean(Class<T> clazz){ return applicationContext.getBean(clazz); }
public static <T> T getBean(String name,Class<T> clazz){ return applicationContext.getBean(name,clazz); } }
|
调用方式如下:
ReminderConfigService reminderConfigService = AppContextUtil.getBean(ReminderConfigService.class);
|
3.2 使用ContextLoader
public class ExampleJob extends QuartzJobBean {
@Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { WebApplicationContext a = ContextLoader.getCurrentWebApplicationContext(); System.out.println(a.getBean(APIController.class)); System.out.println(a.containsBean("APIController"));
}
}
|
3.3 使用 SpringContextHolder(我在项目中使用的)
@Log4j2 public class TestJob implements BaseJob { DtjhEndPoint dtjhEndPoint = SpringContextHolder.getBean(DtjhEndPoint.class);
@Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { log.info("spring组件注入是否成功,{}", dtjhEndPoint.getFilePath()); } }
|