Spring之IOC
- 简介
- 什么是Inversion of Control(IOC)
- Spring的IOC功能
- Spring的IOC层次分析
- Spring的IOC相关注解
- Spring的IOC生命周期相关接口
- Spring的IOC源码分析
简介
Spring框架中最为核心的就是IOC和AOP,本文重点讲解IOC,本文很长,做好途中关闭页面的准备:)
什么是Inversion of Control(IOC)
在现实模型中大部分高层建筑都是需要依赖于底层建筑的。
依赖无倒置:在软件设计里,遵循现实模型,高层模块依赖底层,即底层是接口,高层是实现。依赖无倒置会造成高层模块频繁改动,违背开放封闭原则。
依赖倒置(DIP):在软件设计里,底层模块依赖高层,即高层是接口,底层是实现。 反转控制(IOC):DIP只是一个原则,而IOC是DIP的设计模式。支持IOC框架有Spring等。 依赖注入(DI):是IOC的一种功能,将依赖对象(底层)的创建和绑定转移到被依赖对象(高层)类的外部来实现。
通过IOC容器可以解耦高层和底层模块。
Spring的IOC功能
- 提供Bean的详细生命周期接口以及部分实现;
- 解析Bean相关资源;
- 把Bean信息加载到工厂容器里面;
- 初始化Bean;
- 解决Bean的依赖注入;
- 提供IOC容器的上下文给应用。
其中步骤1对于应用角度而言是非常重要的,需要开发者了解Spring的生命周期,步骤4和5有可能递归,是IOC的核心。
Spring的IOC层次分析
在这里默认读者都会使用Spring的开发注解方式。
Spring的源码非常庞大,在阅读源码之前,一定要有分层的思想,IOC涉及到的主要模块分别是:
- spring-core,底层实现,如资源的解析,这里我不建议浪费太多时间阅读;
- spring-context,上下文相关, 也就是我们平时的注解和Bean的生命周期,是开发者重点关注的模块;
- spring-beans,bean相关,是spring的IOC实质核心;
- spring-aop,动态代理封装与实现。
core我不分析,aop在后续会分析,现在重点分析beans和context。
Context
先分析我们开发者最熟悉的context,以AnnotationConfigApplicationContext为例,以下是类层次图:
其中黄色边框是core包的接口/类,蓝色边框的是beans包的接口/类,其余都是context包的接口/类。
core这里代表是底层代码,不分析。
beans包的接口:
- BeanFactory是获取Bean的最底层的接口,如getBean;
- HierarchicalBeanFactory继承BeanFactory,是一个可继承的工厂接口,这里没有父子容器(Spring MVC有),可无视;
- ListableBeanFactory继承BeanFactory,是一个可以获取bean信息或者根据信息获取bean的接口;
- BeanDefinitionRegistry:注册Bean信息。
AnnotationConfigApplicationContext实现beans的接口是为了上下文可以调用getBean等方法。
context包的接口:
- ApplicationEventPublisher:通知ApplicationEvent事件到应用的监听器,如ContextRefreshedEvent等事件。
- MessageSource:多国语言接口,不做分析。
- Lifecycle:容器start,stop,isRunning的控制接口。
- ApplicationContext:非常核心的上下文,继承了资源解析接口、ApplicationEventPublisher和MessageSource。自身提供暴露自动注入工厂getAutowireCapableBeanFactory接口。
- ConfigurableApplicationContext:继承ApplicationContext和Lifecycle,封装Bean生命周期和控制的接口。
- AbstractApplicationContext:实现ConfigurableApplicationContext的抽象类。
- GenericApplicationContext: 继承注册Bean信息接口,继承AbstractApplicationContext,并且内部引用DefaultListableBeanFactory(BeanFactory)。
- AnnotationConfigRegistry: 通过注解注册Bean信息。
- AnnotationConfigApplicationContext:继承GenericApplicationContext类,实现注解注册Bean信息接口。
spring通过分层,只耦合了少部分beans包的代码,并通过内部变量引用BeanFactory,屏蔽了开发者对BeanFactory访问权。
Beans
对DefaultListableBeanFactory分析,以下是类层次图:
其中黄色边框是core包的接口/类,其余都是beans包的接口/类。
core这里代表是为了管理别名资源,不分析。
beans的接口:
- BeanFactory、HierarchicalBeanFactory、ListableBeanFactory和BeanDefinitionRegistry同上。
- SingletonBeanRegistry:注册单例接口,可解决set注入的循环依赖问题。
- DefaultSingletonBeanRegistry: 注册单例实现类。
- FactoryBeanRegistrySupport: 支持FactoryBean,其中FactoryBean是工厂Bean,可以控制对象的获取。
- ConfigurableBeanFactory: 配置各种Bean的工厂接口,内部Spring使用。
- ConfigurableListableBeanFactory:配置各种Bean通过Interface解析到实现Bean的接口,如通过ApplicationContext.class解析到AnnotationConfigApplicationContext.class,内部Spring使用。
- AbstractBeanFactory:实现ConfigurableBeanFactory接口,继承FactoryBeanRegistrySupport的抽象类,里面有getBean等实现,以及createBean hook方法。
- AutowireCapableBeanFactory:自动注入接口。
- AbstractAutowireCapableBeanFactory:实现AutowireCapableBeanFactory接口,继承AbstractBeanFactory,是Bean工厂和注入的桥梁。
- DefaultListableBeanFactory:继承AbstractAutowireCapableBeanFactory,所有Bean信息都在此工厂,默认被context引用。
DefaultListableBeanFactory的主要作用是为了解决自动注入和为context提供BeanFactory内的bean信息,Bean信息均在字段DefaultListableBeanFactory.beanDefinitionMap。
Spring的IOC相关注解
如今Spring基本是利用注解开发的,特别从Spring Boot开始后,我只列出开发中比较常用的注解。
资源相关
- @Component:组件注解;与@Configuration差别在于@Configuration会动态代理@Bean下的方法;
- @Configuration:包含了@Component,与@Bean配合使用;
- @Bean:作用在@Configuration类上的method,定义一个Bean,可设置注入方式,初始化和销毁方法;
- @Lazy:懒加载,与@Configuration一起作用在类时,内部的@Bean均为懒加载;
- @Primary:多个实现同接口的候选者的时候优先选此注解的候选者;
- @ImportResource:导入xml配置,支持一些只能使用xml的框架;
依赖相关
- @AutoWired:根据type自动注入依赖,若需要根据name需要与@Qualifier配合;
- @Qualifier:根据候选者的name解决多个候选者注入问题;
- @Value:自动注入String类型的变量,可用占位符解析文件资源的key-value,注入value;
生命周期相关
- @PostConstruct:Bean的初始化后方法注解;
- @PreDestroy:Bean的预销毁方法注解;
Spring的IOC生命周期相关接口
普通Bean
- InitializingBean:Bean实现init方法;
- DisposableBean:Bean实现destroy方法;
- Aware:通知Bean,只是标识,无接口;
- BeanFactoryAware:继承Aware,通知Bean设置其BeanFactory;
- ApplicationListener:Bean监听application事件,这个接口在context包里面;
PostProcessor
有点像责任链,也是可以排序且不断调用后面的任务,类似拦截普通Bean。
- BeanFactoryPostProcessor: BeanFactory预处理(在注册预处理后),这个接口在context包里面;
- BeanDefinitionRegistryPostProcessor:BeanFactory注册预处理,这个接口在context包里面;
- BeanPostProcessor:Bean预处理,后处理接口;
- InstantiationAwareBeanPostProcessor:继承BeanPostProcessor,Bean实例化前后处理,注入属性处理;
在BeanFactory外的操作都在Beans包外,可见Spring源码分层还是很明显的,值得我们学习。
测试生命周期代码
以下是测试的代码,包含了IOC的生命周期、Factory的处理和循环依赖等功能,可以利用断点进行Debug。
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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
public class IocTests {
@Test
public void testLifeCycle() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(
LifeCycleConfig.class,
TestBeanPostProcessor.class,
TestBeanFactoryPostProcessor.class);
System.out.println("========================================================");
ctx.registerShutdownHook();
}
}
@Configuration
class LifeCycleConfig {
@Bean(autowire = Autowire.BY_TYPE)
TestBean testBean() {
System.out.println("testBean constructor");
return new TestBean();
}
@Bean
InjectedBean injectedBean() {
System.out.println("injectedBean constructor");
return new InjectedBean();
}
@Bean
BeanA beanA() {
System.out.println("beanA constructor");
return new BeanA();
}
@Bean
BeanB beanB() {
System.out.println("beanB constructor");
return new BeanB();
}
class TestBean implements InitializingBean,
DisposableBean,
BeanFactoryAware,
ApplicationListener<ApplicationEvent> {
private InjectedBean injectedBean;
@PostConstruct
public void customInit() {
System.out.println("testBean customInit");
}
@PreDestroy
public void customDestroy() {
System.out.println("testBean customDestroy");
}
@Override
public void destroy() throws Exception {
System.out.println("testBean destroy");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("testBean afterPropertiesSet");
}
public InjectedBean getInjectedBean() {
return injectedBean;
}
public void setInjectedBean(InjectedBean injectedBean) {
this.injectedBean = injectedBean;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("testBean setBeanFactory " + beanFactory.getClass().getSimpleName());
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
System.out.println("testBean " + event.getClass().getSimpleName());
}
}
class InjectedBean {
}
class BeanA {
private BeanB beanB;
public BeanB getBeanB() {
return beanB;
}
@Autowired
public void setBeanB(BeanB beanB) {
this.beanB = beanB;
}
}
class BeanB {
private BeanA beanA;
public BeanA getBeanA() {
return beanA;
}
@Autowired
public void setBeanA(BeanA beanA) {
this.beanA = beanA;
}
}
}
@Component
class TestBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
if ("testBean".equals(beanName)) {
System.out.println("testBean postProcessBeforeInstantiation");
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
if ("testBean".equals(beanName)) {
System.out.println("testBean postProcessAfterInstantiation");
}
return true;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
if ("testBean".equals(beanName)) {
Arrays.stream(pvs.getPropertyValues()).forEach(p ->
System.out.println("testBean postProcessPropertyValue " + p.toString()));
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("testBean".equals(beanName)) {
System.out.println("testBean postProcessBeforeInitialization");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("testBean".equals(beanName)) {
System.out.println("testBean postProcessAfterInitialization");
}
return bean;
}
}
@Component
class TestBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
System.out.println("testBeanFactory postProcessBeanDefinitionRegistry " + registry.getClass().getSimpleName());
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("testBeanFactory postProcessBeanFactory " + beanFactory.getClass().getSimpleName());
}
}
根据输出信息即可知道生命周期,其输出信息:
testBeanFactory postProcessBeanDefinitionRegistry DefaultListableBeanFactory
testBeanFactory postProcessBeanFactory DefaultListableBeanFactory
testBean postProcessBeforeInstantiation
testBean constructor
testBean postProcessAfterInstantiation
injectedBean constructor
testBean postProcessPropertyValue bean property 'injectedBean'
testBean setBeanFactory DefaultListableBeanFactory
testBean postProcessBeforeInitialization
testBean customInit
testBean afterPropertiesSet
testBean postProcessAfterInitialization
beanA constructor
beanB constructor
testBean ContextRefreshedEvent
========================================================
testBean ContextClosedEvent
testBean customDestroy
testBean destroy
Spring的IOC源码分析
根据上面的生命周期的测试代码来分析IOC源码,这里不会层层深入;
1
2
3
4
5
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
this(); // 添加注解的解析器
register(annotatedClasses); // 将注解的解析器注册到IOC容器中
refresh(); // 更新容器
}
注解的解析器
1
2
3
4
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this); // 解析@Configuration等注解
this.scanner = new ClassPathBeanDefinitionScanner(this); // 解析@Scan注解,这里没有使用@Scan
}
这里只用到reader,忽略scanner,AnnotatedBeanDefinitionReader做了以下初始化逻辑:
- DefaultListableBeanFactory.dependencyComparator = AnnotationAwareOrderComparator,工厂的比较器,如@Order的先后顺序,实现利用了饿汉式单例设计模式;
- DefaultListableBeanFactory.autowireCandidateResolver = ContextAnnotationAutowireCandidateResolver,注入候选者Bean的解析,如@AutoWired同类型多Bean的选取;
- 通过DefaultListableBeanFactory.registerBeanDefinition注册6个bean;
- ConfigurationClassPostProcessor实现BeanDefinitionRegistryPostProcessor接口,包含BeanFactory前后处理和增强BeanFactory注解资源,如@Configuration;
- AutowiredAnnotationBeanPostProcessor实现InstantiationAwareBeanPostProcessor,主要是注入属性处理@AutoWired和@Value;
- RequiredAnnotationBeanPostProcessor实现InstantiationAwareBeanPostProcessor,主要是注入属性处理@Required;
- CommonAnnotationBeanPostProcessor实现InstantiationAwareBeanPostProcessor(在context包,可见是Spring的扩展),主要是注入属性处理@PostConstruct和@PreDestroy;
- EventListenerMethodProcessor事件监听器处理,主要是@EventListener,一般很少用,都是回调Bean的事件方法,而不会回调某个方法;
- DefaultEventListenerFactory事件监听器工厂配合事件监听器处理;
AnnotationConfigApplicationContext初始化完成后,所有注解相关的Bean信息已经添加到beanFactory,同时添加了ConfigurationClassPostProcessor预处理,这个类有两个作用:
- 在BeanFactory注册阶段解析@Configuration里面的@Bean和其他注解。
- 在后续处理BeanFactory阶段,通过cglib动态代理增强了@Bean注解方法,使得后续初始阶段调用注解下的方法。
注册注解类
register(annotatedClasses)会调用doRegisterBean,注册注解类的信息,会把@Primary、@Lazy等注解信息注册AnnotatedBeanDefinition里,没有什么难度,不做详细介绍。
更新容器
更新容器的代码最为复杂,也是重点分析的部分。
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
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// 初始化context环境变量
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
// 获得BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
// 配置BeanFactory的EL表达式解析和Resource资源获取,添加系统环境变量和属性单例到spring容器
// 添加ApplicationContextAwareProcessor,在Bean初始化前后处理各种Aware接口
// 添加ApplicationListenerDetector,在Bean初始化前把内部Bean转化为ApplicationListeners。
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
// 对于AnnotationConfigApplicationContext是空操作
// 对于GenericWebApplicationContext会初始化servlet和环境的Bean
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
// 实例化实现BeanDefinitionRegistryPostProcessor的类,这里是ConfigurationClassPostProcessor
// 调用BeanFactory注册的预操作和预处理
// 实例化实现BeanFactoryPostProcessor的类
// 调用BeanFactory的预处理
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
// 实例化实现BeanPostProcessor的类
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
// 初始化多国语言
initMessageSource();
// Initialize event multicaster for this context.
// 注册并实例化SimpleApplicationEventMulticaster,监听Bean的ApplicationListener
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
// 空操作
onRefresh();
// Check for listener beans and register them.
// 添加实现ApplicationListener的Bean信息,以作为后续回调
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
// 注册并实例化非@Lazy的普通Bean,BeanPostProcessor在前面已经实例化完成
// 会涉及到属性注入的问题,下文会分析
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
// 完成实现Lifecycle接口Bean的回调(应用层用得很少)
// 通知所用实现ApplicationListener的Bean事件ContextRefreshedEvent
finishRefresh();
}
// ......
}
}
大概逻辑可认为:
- 初始化context环境变量和把系统的环境变量等资源实例化成Bean交给Spring管理。
- 通过实现了BeanDefinitionRegistryPostProcessor的ConfigurationClassPostProcessor解析@Configuration,把里面的@Bean方法,@ComponentScan等注解下的信息或者直接导入xml添加到DefaultListableBeanFactory.beanDefinitionMap。
- 按PriorityOrdered、Ordered和无序等顺序序实例化实现BeanFactoryPostProcessor的类,ConfigurationClassPostProcessor也是实现了这个接口,会对@Bean下的方法通过cglib动态代理并设置RootBeanDefinition.factoryMethodName,使其在实例化阶段被调用。
- 按PriorityOrdered、Ordered和无序等顺序序实例化BeanPostProcessor。
- 注册并实例化事件广播。
- 添加监听实现ApplicationListener的Bean的事件。
- Bean信息已经都在DefaultListableBeanFactory.beanDefinitionMap,且BeanPostProcessors已经准备就绪,此时可以实例化非Lazy的Bean,并解决注入属性问题。
- Bean实例化完成,监听器已经准备就绪,可以通知Bean了。
这里不详细分析ConfigurationClassPostProcessor,大部分是注解解析内容,感兴趣可以自行根据测试样例添加断点Debug并查看源代码。
实例化容器
实例化过程会调用doGetBean方法。省略与测试代码无关的源码如下:
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
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
// 转化beanName
final String beanName = transformedBeanName(name);
Object bean;
// Eagerly check singleton cache for manually registered singletons.
// 获取还没有完全注入属性但已经构造成功的实例
// 可解决循环依赖
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//.......
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
return createBean(beanName, mbd, args);
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//.......
}
return (T) bean;
}
```java
通过以上简略代码可知:
1. 若有循环依赖现象则获取已经构造成功的单例。
2. 否则利用getSingleton的匿名内部类回调createBean,预处理实例化,处理可能存在的代理对象,最后调用doCreateBean。
3. 无论如何都会执行getObjectForBeanInstance,处理实现FactoryBean的类。
继续查看doCreateBean省略与测试代码无关的源码:
```java
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean.
BeanWrapper instanceWrapper = null;
// 实例化Bean,并对Bean装饰,处理后续操作field
// 实例化可通过@Bean下的method,即RootBeanDefinition.getFactoryMethodName(之前流程已经解析到RootBeanDefinition)
// 或普通的构造方法,有参或无参
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
// 解决循环依赖Bean,通过beanName映射singletonFactories
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
// Initialize the bean instance.
Object exposedObject = bean;
// 通过装饰对象对依赖属性进行注入
// 如@Bean下method的参数、@Bean(autowire)和@Autowired下field和setField注入依赖Bean
// 后处理实例化
populateBean(beanName, mbd, instanceWrapper);
// 此时Bean是完整对象,预处理初始化、自定义初始化、后处理初始化。
exposedObject = initializeBean(beanName, exposedObject, mbd);
// ......
return exposedObject;
}
通过以上简略代码可知:
- doCreateBean方法前已经预处理实例化对象,创建出新对象。
- 注入依赖属性后,后处理实例化对象。
- Bean已经实例化完成, 进一步初始化,完成后即可暴露外部。
过程均是在DefaultListableBeanFactory这个类里面实现的,从Beans层次图可以得知,继承了AbstractAutowireCapableBeanFactory,AbstractAutowire实现注入属性。 DefaultListableBeanFactory里面还实现了注入依赖的候选Bean,详情可以查看其代码。