使用 ApplicationContextAware 定义 SpringContextHolder 类
需求:使用 @autowired注入一些对象,但发现不可以直接使用@Autowired,因为方法是static的,要使用该方法当前对象也必须是static,正常情况下@Autowired无法注入静态的bean,于是发现项目中用到了springContextHolder,通过使用
private T t= SpringContextHolder.getBean(T.class);
或者我们在刚开始学习的时候,会使用如下这种方式来获取 Bean。但是这样就会存在一个问题,因为它需要重新装载 spring-core.xml 文件,并实例化上下文bean,如果有些线程配置类也是在这个配置文件中,那么会造成做相同工作的的线程会被启两次。一次是 web容器初始化时启动,另一次是上述代码显示的实例化了一次。这样就产生了冗余。下面就来说说解决方案。
ApplicationContext appContext = new ClassPathXmlApplicationContext("spring-core.xml"); T t = (T)appContext.getBean("t");
一、SpringContextHolder 工具类
自定义 SpringContextHolder 工具类,全网统一模板。需要将该类注入到 Spring IOC 中。因此路径很重要。
1 package com.zzx.utils; 2 3 import lombok.extern.slf4j.Slf4j; 4 import org.springframework.beans.BeansException; 5 import org.springframework.beans.factory.DisposableBean; 6 import org.springframework.context.ApplicationContext; 7 import org.springframework.context.ApplicationContextAware; 8 9 /** 10 * @author 11 * @date 12 */ 13 @Component 14 @Slf4j 15 public class SpringContextHolder implements ApplicationContextAware, DisposableBean { 16 17 private static ApplicationContext applicationContext = null; 18 19 /** 20 * 取得存储在静态变量中的ApplicationContext. 21 */ 22 public static ApplicationContext getApplicationContext() { 23 assertContextInjected(); 24 return applicationContext; 25 } 26 27 /** 28 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. 29 */ 30 public static <T> T getBean(String name) { 31 assertContextInjected(); 32 return (T) applicationContext.getBean(name); 33 } 34 35 /** 36 * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型. 37 */ 38 public static <T> T getBean(Class<T> requiredType) { 39 assertContextInjected(); 40 return applicationContext.getBean(requiredType); 41 } 42 43 /** 44 * 检查ApplicationContext不为空. 45 */ 46 private static void assertContextInjected() { 47 if (applicationContext == null) { 48 throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" + 49 ".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder."); 50 } 51 } 52 53 /** 54 * 清除SpringContextHolder中的ApplicationContext为Null. 55 */ 56 public static void clearHolder() { 57 log.debug("清除SpringContextHolder中的ApplicationContext:" 58 + applicationContext); 59 applicationContext = null; 60 } 61 62 @Override 63 public void destroy() throws Exception { 64 SpringContextHolder.clearHolder(); 65 } 66 67 @Override 68 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 69 if (SpringContextHolder.applicationContext != null) { 70 log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext); 71 } 72 SpringContextHolder.applicationContext = applicationContext; 73 } 74 }
二、ApplicationContextAware接口
Spring容器初始化的时候会检测容器中的所有Bean,如果发现某个Bean实现了ApplicationContextAware接口,Spring容器会在创建该Bean之后,自动调用该 Bean的 setApplicationContextAware()方法,调用该方法时,会将容器本身作为参数传给该方法,该方法将 Spring传入的参数(容器本身)赋给该类对象的 applicationContext实例变量,因此接下来可以通过该applicationContext实例变量来访问容器本身。