记录遇到监听器无法使用@Autowired和@Resource注入对象的问题
-
遇到的问题
今天尝试做一个导入和导出表格的功能,使用的工具是阿里提供的easyexcel,导出的功能按照实例很快就做出来了,但是做导入的功能时一直都显示注入的Mapper为空
-
寻找问题的思路
- 按照往常的经验我首先去检查了启动类上是否加了@MapperScan注解,发现加了并且路径也正确,为了保险起见我在为空的Mapper类上分别尝试了@Mapper与@Repository注解进行尝试,发现无效
- 我想知道是否是这个Mapper类的问题,因此在一个测试类中使用了@Autowired注入了这个Mapper类并测试了一些方法,发现可以正常使用,因此排除Mapper注入失败这个问题
- 既然排除了Mapper注入失败的问题那就应该观察Mapper类被注入的类中是否有什么问题,然后我搜索了com.alibaba.excel.event.AnalysisEventListener这个类中为什么注入不了Bean对象,大佬们还是给力的,然后就发现了是因为监听器内中无法直接使用@Autowired和@Resource注入
-
解决问题的方法
网上有很多遇到这个问题的人,因此也有对应的解决方案,通用的解决方案是创建一个单例的IOC容器工具类,让其他类可以方便地通过类名或者类的class对象去获取对应的bean,代码如下:
import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component; import java.util.Map; /** * SpringApplicationUtils * 使用IOC容器获取bean对象 * @author wcl76 * @date 2022/11/10 */ @Component //通过上下文获取到实例bean public class SpringApplicationUtils implements ApplicationContextAware { private static ApplicationContext applicationContext = null; /** * 获取applicationContext * * @return */ public static ApplicationContext getApplicationContext() { return applicationContext; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { if (SpringApplicationUtils.applicationContext == null) { SpringApplicationUtils.applicationContext = applicationContext; } } /** * 通过name获取 Bean. */ public static Object getBean(String name) { return getApplicationContext().getBean(name); } /** * 通过class获取Bean. * * @param clazz * @param <T> * @return */ public static <T> T getBean(Class<T> clazz) { return getApplicationContext().getBean(clazz); } /** * 通过name,以及Clazz返回指定的Bean * * @param name * @param clazz * @param <T> * @return */ public static <T> T getBean(String name, Class<T> clazz) { return getApplicationContext().getBean(name, clazz); } /** * 获取指定类型的所有bean实例 * * @param clazz * @param <T> * @return */ public static <T> Map<String, T> getBeansOfType(Class<T> clazz) { return getApplicationContext().getBeansOfType(clazz); } } -
最后的总结
在Listener监听器中无法使用Spring容器的@Resource或者@Autowired 注解的方法注入bean,因为,在web Server容器中,无论是Servlet,Filter,还是Listener都不是Spring容器管理的,因此我们都无法在这些类中直接使用Spring注解的方式来注入我们需要的对象。在这里,Servlet的整个生命周期都是由Servlet容器来处理的。如果把它硬放到Spring容器中去创建,Servlet对象是可被Spring容器建出来,但Servlet容器可能跟本就不知道这个Servlet是否存在,因为不在它自己的容器中。所以,servlet交给web server来管理,不要交给spring管理。