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