文章目录
  1. 1. IOC简介
  2. 2. 运行环境
  3. 3. 内部工作机制
  4. 4. IOC流水线
    1. 4.1. 总结
  5. 5. 材料类和工具类介绍
    1. 5.1. BeanDefinition
    2. 5.2. InstantiationStrategy
    3. 5.3. BeanWrapper
  6. 6. 总结

IOC简介

IOC(Inverse Of Control,控制反转)是Spring容器的核心,AOP、声明式事物都是基于该功能。Spring IOC装配好Bean,并建立Bean和Bean之间的关联关系。

运行环境

  • OS:win8.1
  • idea:IntelliJ IDEA 2017
  • java version:1.8.0_91 b4 bit
  • 参考资料:《Spring4.x++企业应用开发实战》,《深入分析Java Web技术内幕》
  • 使用的pom:
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
?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.smart</groupId>
<artifactId>chapter6</artifactId>
<version>1.0</version>
<dependencies>
<!-- spring 依赖-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>${commons-lang.version}</version>
</dependency>
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>${commons-dbcp.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>${testng.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
<configuration>
<forkMode>once</forkMode>
<threadCount>10</threadCount>
<argLine>-Dfile.encoding=UTF-8</argLine>
</configuration>
</plugin>
</plugins>
</build>
<properties>
<file.encoding>UTF-8</file.encoding>
<spring.version>4.2.2.RELEASE</spring.version>
<testng.version>6.8.7</testng.version>
<aopalliance.version>1.0</aopalliance.version>
<commons-codec.version>1.9</commons-codec.version>
<commons-lang.version>2.0</commons-lang.version>
<commons-dbcp.version>1.4</commons-dbcp.version>
<mysql.version>5.1.29</mysql.version>
</properties>
</project>

内部工作机制

我们通过如下方式加载Spring的配置文件,创建IOC容器

1
ctx = new ClassPathXmlApplicationContext(CONFIG_FILES);

我们进入源码发现,ClassPathXmlApplicationContext类的构造方法最终调用的就是org.springframework.context.support.AbstractApplicationContext#refresh 方法,该方法清楚的描绘了Spring容器启动所执行的各项操作

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
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为刷新准备新的Context.
prepareRefresh();
// 刷新所有的BeanFactory的子容器
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 通过当前Context创建BeanFactory.
prepareBeanFactory(beanFactory);
try {
// 注册实现了BeanPostProcessor接口的bean
postProcessBeanFactory(beanFactory);
// 初始化和执行BeanFactoryPostProcessor beans.
invokeBeanFactoryPostProcessors(beanFactory);
// 初始化和执行BeanPostProcessors beans
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource.
initMessageSource();
// 初始化event multicaster.
initApplicationEventMulticaster();
// 刷新由子类实现的方法.
onRefresh();
// 注册事件监听器.
registerListeners();
// 初始化所有单例bean.
finishBeanFactoryInitialization(beanFactory);
// 完成刷新操作.
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

IOC流水线

Spring协调多个组件完成该复杂的流程,如下图描述了Spring容器从加载配置文件到创建一个完整Bean的流程和参与类。

流水线

  • ResourceLoader从存储位置加载spring配置文件到Resource对象,这个时候Resource对象就表示该spring配置文件
  • BeanDefinitionReader 通过Resource对象解析配置文件,将每一个<bean> 标签解析为一个BeanDefinition 对象,并保存到 BeanDefinitionRegistry 对象中,这个时候的 BeanDefinition 对象是没有进行加工的
  • 容器扫描 BeanDefinitionRegistry 对象中的 BeanDefinition 对象,通过Java反射机制自动识别出实现了BeanFactoryPostProcessor 接口的bean,然后调用这个处理器对 BeanDefinitionRegistry 中的 BeanDefinition 进行加工处理。主要完成下面两个任务:
    • 对使用占位符的<bean> 元素标签进行解析,并得到最终的值
    • BeanDefinitionRegistry 中定义的 BeanDefinition 通过反射机制找出所有属性编辑器Bean,并自动将它们注册到Spring容器的属性编辑器注册表中
  • Spring容器从 BeanDefinitionRegistry 中获取加工后的bean,调用InstantiationStrategy 着手进行Bean实例化,这个时候的实例化的bean还没有进行属性设置
  • 在实例化Bean时,Spring容器使用BeanWrapper 对Bean进行封装。BeanWrapper 类提供了很多反射操作Bean的方法,结合对应bean的BeanDefinition 及容器中的属性编辑器,完成Bean属性的注入工作。
  • 最后一个就是收尾工作,通过实现了BeanPostProcessor 接口的bean对已完成属性设置工作的bean进行处理,得到一个准备就绪的Bean

总结

通过上面的描述,我们其实可以将上面的IOC的工作比作流水线,在流水线上有两个主要的工具,一个是待加工的原材料,一个加工的工具。Spring组件按照承担的角色可以分为:

  • 原材料类:ResourceBeanDefinitionPropertyEditor 以及最终产品 bean
  • 工具类:ResourceLoaderBeanDefinitionReaderBeanFactoryPostProcessorInstantiationStrategyBeanWrapperBeanPostProcessor

材料类和工具类介绍

BeanDefinition

org.springframework.beans.factory.config.BeanDefinition 是配置文件<bean>元素标签在容器的内部表示。<bean> 标签元素拥有class、scope、lazy-init等配置属性,BeanDefinition则提供了相应的beanClass、scope、lazyInit属性。 BeanDefinition类的继承结构如下图:

BeanDefinition的继承结构

RootBeanDefinition 是常见的的实现类,他对应一般的 <bean> 元素标签。在Spring配置文件中可以定义父<bean> 和 子 <bean>,父bean用RootBeanDefinition表示,子bean用ChildBeanDefinition表示,而没有父bean的bean则用RootBeanDefinition 表示;AbstractBeanDefinition 对两者共同的类信息进行抽取。

Spring 通过BeanDefinition 将配置文件中的<bean> 转化为容器的内部表示,并将这些BeanDefinition 注册到 BeanDefinitionRegistry 中。一般情况下,BeanDefinition只在容器启动时加载并解析,除非容器刷新或重启,否则这些信息不会发生变化。创建BeanDefinition主要包括如下两个步骤:

  • 利用BeanDefinitionReader 读取承载配置文件信息的Resource 对象,通过xml解析DOM对象,简单的为每一个<bean> 标签生成对应的 BeanDefinition 对象。但是这个时候的 BeanDefinition 还是一个半成品,还有一些占位符没有被解析出来。
  • 第二步,利用容器中注册的BeanFactoryPostProcessor 对半成品的BeanDefinition 进行处理,获得一个完整的 BeanDefinition 对象。

InstantiationStrategy

org.springframework.beans.factory.support.InstantiationStrategy 负责根据BeanDefinition 对象创建一个Bean实例。InstantiationStrategy 类的继承结构如下:

InstantiationStrategy类的继承结构

SimpleInstantiationStrategy 是最常用的实例化策略,该策略利用Bean实现类的默认构造函数、带参数构造函数或者工厂方法创建Bean的实例。

CglibSubclassingInstantiationStrategy 扩展了 SimpleInstantiationStrategy ,为需要进行方法注入的Bean提供了支持。它利用CGLib类库为Bean动态生成子类。

InstantiationStrategy 只负责实例化Bean的操作,相当于Java中的new的功能,它不会参与Bean属性的设置工作。所以由InstantiationStrategy 返回的bean实际上是一个半成品的bean

BeanWrapper

org.springframework.beans.BeanWrapper 是Spring中重要的组件。BeanWrapper 相当于一个代理器,Spring委托BeanWrapper 完成Bean属性的填充工作。BeanWrapper类的继承结构如下图:

BeanWrapper类的继承结构图

通过上图可以看出BeanWrapper 接口有两个顶级接口PropertyAccessorPropertyEditorRegistryPropertyAccessor 接口定义访问Bean属性的方法,而PropertyEditorRegistry 是属性编辑器的注册表,可以添加一些自定义的PropertyEditor 。所最终实现的BeanWrapperImpl 类具有:

  • Bean包裹器
  • 属性访问方法
  • 属性编辑器注册方法

总结

对Spring的Ioc容器来说,主要有BeanFactoryPostProcessorBeanPostProcessor ,它们分别在构建BeanFactory和Bean时调用。还有initializingBeanDisposableBean ,它们分别在Bean实例创建和销毁时调用。通过这些特定的扩展点可以实现我们个性化的需求。

文章目录
  1. 1. IOC简介
  2. 2. 运行环境
  3. 3. 内部工作机制
  4. 4. IOC流水线
    1. 4.1. 总结
  5. 5. 材料类和工具类介绍
    1. 5.1. BeanDefinition
    2. 5.2. InstantiationStrategy
    3. 5.3. BeanWrapper
  6. 6. 总结