@Autowired注入失效问题
背景:
在编写EasyExcel示例代码时,执行程序报NullPointerException
,经排查发现是自定义的ExcelListener监听器
中注入UserService
失败导致。
还有一种情况是因为包没被扫到导致。Spring Boot项目的Bean装配默认规则是根据Application类(指项目入口类)所在的包位置从上往下扫描,该情况大家自行了解,本文不做赘述。
解决方案:
方案1:@Autowired(推荐)
调用方:
@Autowired
private ExcelListener excelListener;
EasyExcel.read(excel.getInputStream(), User.class, excelListener).sheet().doRead();
被调用方:
@Component
public class ExcelListener extends AnalysisEventListener {
private static final Logger LOGGER = LoggerFactory.getLogger(ExcelListener.class);
@Autowired
private UserService userService;
调用方通过Spring注入的方式自动注入ExcelListener ,而非new的方式,这样获取到的ExcelListener是被Spring容器管理的,进而可以在ExcelListener中通过
@Autowired
的方式成功获取到同样被Spring容器管理的UserService,因为UserService 的实现类中有”@Service”注解标记。
另外要记得被调用的类要加上"@Component"
注解,不然该类依然不会被Spring容器管理,类中Autowired的属性仍将注入失败。
方案2:构造器注入
调用方:
EasyExcel.read(excel.getInputStream(), User.class, new ExcelListener()).sheet().doRead();
被调用方:
@Component
public class ExcelListener extends AnalysisEventListener {
private static UserService userService;
public ExcelListener() {
}
@Autowired
public ExcelListener(UserService userService) {
this.userService = userService;
}
构造器注入的方式解决了当调用方调用一个未被Spring容器管理的类时的问题。
可以看到调用方是通过"new ExcelListener()"
的方式调用的ExcelListener,该方式ExcelListener类是未被Spring容器管理的,通过构造器注入的方式可以解决该问题,但需注意的是”@Autowired”是写在有参构造器上的,而非属性,且私有属性应为”static”静态的,不然会注入失败。
方案3:创建上下文工具类获取SpringIOC容器中的类
定义工具类:
package com.lee.demo.easyexcel.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/** * @ClassName: ApplicationContextUtil * @Author: Jimmy * @Date: 2020/1/15 14:43 * @Description: 上下文工具类,用于获取SpringIOC容器中的类 */
@Component
public class ApplicationContextUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext = null;
/** * 获取ApplicationContext上下文 */
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (ApplicationContextUtil.applicationContext == null) {
ApplicationContextUtil.applicationContext = applicationContext;
}
}
/** * 通过名称获取实体类 */
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
}
通过工具类获取实体:
public void saveData() {
UserService userService = (UserServiceImpl) ApplicationContextUtil.getBean("userServiceImpl");
userService.saveBatch(this.list,BATCH_COUNT);
}
常用的@Controller、@Service、@Repository、@Component都表示将Bean交给Spring管理,所以Spring的ApplicationContext肯定是有实现类UserServiceImpl的,通过定义的getBean()方法获取即可,参数即要获取的类的名称,注意首字母要小写。
参考:https://www.jianshu.com/p/f3c67ca457e6
还没有评论,来说两句吧...