监听器Listener中使用spring容器管理的bean,解决Autowired为null空指针的问题

背景: 在整合EasyExcel时候,自定义了监听器SubjectExcelListener,在监听器里面完成插入等操作,插入操作是通过mybatisPlus的条件构造器完成的,需要注入自定义的subjectService来完成,但是直接在监听器里使用@Auwowired注入subjectService,会报空指针。
原因如下:
首先要区分Listener的生命周期和spring管理的bean的生命周期。
(1)Listener的生命周期是由servlet容器(例如tomcat)管理的,项目启动时上例中的ConfigListener是由servlet容器实例化并调用其contextInitialized方法,而servlet容器并不认得@Autowired注解,因此导致ConfigService实例注入失败。
(2)而spring容器中的bean的生命周期是由spring容器管理的。
在web Server容器中,无论是Servlet,Filter,还是Listener都不是Spring容器管理的,因此我们都无法在这些类中直接使用Spring注解的方式来注入我们需要的对象

解决方法:
方法一:通过构造参数注入:
首先在controller层注入subjectService,将其作为参数,传递到saveSubject方法中

    @Autowired
    private EduSubjectService subjectService;
    //添加课程分类
    @ApiOperation(value = "Excel批量导入")
    @PostMapping("addSubject")
    public R addSubject(MultipartFile file) {
        //1 获取上传的excel文件 MultipartFile
        //返回错误提示信息
        subjectService.saveSubject(file,subjectService);
        //判断返回集合是否为空
        return R.ok();
    }

然后在实现类中在new监听器的时候,作为参数传递给SubjectExcelListener

@Override
    public void saveSubject(MultipartFile file, EduSubjectService subjectService) {
        try {
            //1 获取文件输入流
            InputStream inputStream = file.getInputStream();

            // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
            EasyExcel.read(inputStream, SubjectData.class, new SubjectExcelListener(subjectService)).sheet().doRead();
        }catch(Exception e) {
            e.printStackTrace();
            throw new GuliException(20002,"添加课程分类失败");
        }
    }

这里视频中做的略微麻烦了,其实在controller中不用注入subjectService和传参,而是在subjectService实现类中new SubjectExcelListener的时候,直接传递this即可,如下:
监听器Listener中使用spring容器管理的bean,解决Autowired为null空指针的问题_第1张图片
在SubjectExcelListener监听器中,声明subjectService和它的有参无参构造,
监听器Listener中使用spring容器管理的bean,解决Autowired为null空指针的问题_第2张图片
在下面业务中即可正常使用subjectService
监听器Listener中使用spring容器管理的bean,解决Autowired为null空指针的问题_第3张图片
方法二:
写一个bean类BeanContext,从spring的上下文WebApplicationContext 中获取

public class BeanContext implements ApplicationContextAware {

    private static ApplicationContext applicationContext;

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        BeanContext.applicationContext = applicationContext;
    }

    public static ApplicationContext getApplicationContext(){
        return applicationContext;
    }

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name) throws BeansException {
        return (T)applicationContext.getBean(name);
    }

    public static <T> T getBean(Class<T> clz) throws BeansException {
        return (T)applicationContext.getBean(clz);
    }

}

在监听器里面调用:

EduSubjectService subjectService= BeanContext.getApplicationContext().getBean(EduSubjectService.class);

即可完成调用
监听器Listener中使用spring容器管理的bean,解决Autowired为null空指针的问题_第4张图片

测试,成功插入:
监听器Listener中使用spring容器管理的bean,解决Autowired为null空指针的问题_第5张图片

监听器Listener中使用spring容器管理的bean,解决Autowired为null空指针的问题_第6张图片

你可能感兴趣的:(java踩坑之路,spring,容器,java)