前言
最近在测试easyExcel工具类时 , 需要自定义一个Listener类用于执行对从excel表中读取到的数据进行入库操作(持久层框架为Mybatis-Plus) . 在程序运行过程中 , 发现通过@Autowired
注解注入Mapper对象为null
, 从而导致了执行插入记录操作时 报了空指针异常 , 具体代码如下 :
/**
* @Author: WuKun
* @Date: 2019/5/24 17:27
*/
@Component
public class ProductCmsExcelVOListener extends ExcelListener<ProductCmsExcelVO> {
@Autowired
private ProductMapper productMapper;
@Override
@Transactional
public void doSomething(ProductCmsExcelVO object, AnalysisContext context) {
//入库操作...
}
}
问题定位
首先确保该Listener类已添加
@Component
注解 √Listener类已在
@ComponentScan
注解指定的扫描路径下 (ps. Spring Boot默认是从启动类所在位置往下扫描) √Mapper接口已在
@MapperScan
注解指定的扫描路径下 √Listener对象 不能通过手动new 的方式创建 ×
由于我原来在创建ProductCmsExcelVOListener对象时 , 是通过ProductCmsExcelVOListener.class字节码对象的newInstance()
方法去创建对象的 , 实质等价于直接new一个该对象 , 从而导致ProductCmsExcelVOListener 的Bean没有被 Spring 管理 , 这也是问题所在 .
解决方式
- 在创建ProductCmsExcelVOListener对象时 , 同样通过
@Autowired
的方式注入 , 而不是自己手动new. - 当然也可以使用比较原始的方法进行去获取Bean , 如ApplicationContext 的
getBean(beanName);
的方式.
总结
@Autowired
注入对象失效的主要有如下两种情况 :
- 第一种如上所述 , 调用者本身不能直接通过new的方式创建 . 例如B是A中通过
@Autowired
注入的成员属性 , 当A是通过手动new的方式创建对象时 , B的注入会失效 . - 另一种情况如上面问题定位的第二点所述 , Spring Boot 默认Bean扫描策略是从Application启动类所在位置往下扫描 , 当项目存在多个Spring Boot 模块时 , 需要保证其他模块中添加了
@Component
注解的类已在Spring Boot的扫描路径范围内 , 必要时需要使用@ComponentScan("com.xx.xx")
注解方式扩大Bean的扫描范围 , 而不是使用Spring Boot 默认的扫描策略 .
参考链接 :