使用 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实例变量来访问容器本身。

posted @ 2020-11-14 17:54  Java程序员进阶  阅读(108)  评论(0编辑  收藏  举报