前言
最近在测试easyExcel工具类时 , 需要自定义一个Listener类用于执行对从excel表中读取到的数据进行入库操作(持久层框架为Mybatis-Plus) . 在程序运行过程中 , 发现通过@Autowired注解注入Mapper对象为null , 从而导致了执行插入记录操作时 报了空指针异常 , 具体代码如下 :
/**
* @Author: WuKun
* @Date: 2019/5/24 17:27
*/
@Component
public class ProductCmsExcelVOListener extends ExcelListener {
@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 默认的扫描策略 .
参考链接 :
- https://www.jianshu.com/p/f3c67ca457e6
吴焜
广州芦苇科技Java开发团队
芦苇科技-广州专业软件外包服务公司
提供微信小程序、APP应用研发、品牌设计等专业服务,专注于互联网产品咨询、品牌设计、技术研发等领域