@Autowired注入失效问题

妖狐艹你老母 2023-06-30 05:26 110阅读 0赞

背景:

在编写EasyExcel示例代码时,执行程序报NullPointerException,经排查发现是自定义的ExcelListener监听器中注入UserService失败导致。

还有一种情况是因为包没被扫到导致。Spring Boot项目的Bean装配默认规则是根据Application类(指项目入口类)所在的包位置从上往下扫描,该情况大家自行了解,本文不做赘述。

解决方案:

方案1:@Autowired(推荐)

调用方:

  1. @Autowired
  2. private ExcelListener excelListener;
  3. EasyExcel.read(excel.getInputStream(), User.class, excelListener).sheet().doRead();

被调用方:

  1. @Component
  2. public class ExcelListener extends AnalysisEventListener {
  3. private static final Logger LOGGER = LoggerFactory.getLogger(ExcelListener.class);
  4. @Autowired
  5. private UserService userService;

调用方通过Spring注入的方式自动注入ExcelListener ,而非new的方式,这样获取到的ExcelListener是被Spring容器管理的,进而可以在ExcelListener中通过@Autowired的方式成功获取到同样被Spring容器管理的UserService,因为UserService 的实现类中有”@Service”注解标记。
另外要记得被调用的类要加上"@Component"注解,不然该类依然不会被Spring容器管理,类中Autowired的属性仍将注入失败。

方案2:构造器注入

调用方:

  1. EasyExcel.read(excel.getInputStream(), User.class, new ExcelListener()).sheet().doRead();

被调用方:

  1. @Component
  2. public class ExcelListener extends AnalysisEventListener {
  3. private static UserService userService;
  4. public ExcelListener() {
  5. }
  6. @Autowired
  7. public ExcelListener(UserService userService) {
  8. this.userService = userService;
  9. }

构造器注入的方式解决了当调用方调用一个未被Spring容器管理的类时的问题。
可以看到调用方是通过"new ExcelListener()"的方式调用的ExcelListener,该方式ExcelListener类是未被Spring容器管理的,通过构造器注入的方式可以解决该问题,但需注意的是”@Autowired”是写在有参构造器上的,而非属性,且私有属性应为”static”静态的,不然会注入失败。

方案3:创建上下文工具类获取SpringIOC容器中的类

定义工具类:

  1. package com.lee.demo.easyexcel.utils;
  2. import org.springframework.beans.BeansException;
  3. import org.springframework.context.ApplicationContext;
  4. import org.springframework.context.ApplicationContextAware;
  5. import org.springframework.stereotype.Component;
  6. /** * @ClassName: ApplicationContextUtil * @Author: Jimmy * @Date: 2020/1/15 14:43 * @Description: 上下文工具类,用于获取SpringIOC容器中的类 */
  7. @Component
  8. public class ApplicationContextUtil implements ApplicationContextAware {
  9. private static ApplicationContext applicationContext = null;
  10. /** * 获取ApplicationContext上下文 */
  11. public static ApplicationContext getApplicationContext() {
  12. return applicationContext;
  13. }
  14. @Override
  15. public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
  16. if (ApplicationContextUtil.applicationContext == null) {
  17. ApplicationContextUtil.applicationContext = applicationContext;
  18. }
  19. }
  20. /** * 通过名称获取实体类 */
  21. public static Object getBean(String name) {
  22. return getApplicationContext().getBean(name);
  23. }
  24. }

通过工具类获取实体:

  1. public void saveData() {
  2. UserService userService = (UserServiceImpl) ApplicationContextUtil.getBean("userServiceImpl");
  3. userService.saveBatch(this.list,BATCH_COUNT);
  4. }

常用的@Controller、@Service、@Repository、@Component都表示将Bean交给Spring管理,所以Spring的ApplicationContext肯定是有实现类UserServiceImpl的,通过定义的getBean()方法获取即可,参数即要获取的类的名称,注意首字母要小写。

参考:https://www.jianshu.com/p/f3c67ca457e6

发表评论

表情:
评论列表 (有 0 条评论,110人围观)

还没有评论,来说两句吧...

相关阅读

    相关 @Autowired 失效

    @Autowired 失效 如果类B中存在成员属性p, p是通过@Autowired自动注入,而类B的实例是通过new的方式产生的,那么自动注入会失效的 比方说,有一个