Spring框架IOC源码分析

Spring 模块的手写分析


Spring 源码阅读注意事项:try catch 和 do开头的方法 重点阅读

BeanFactory 基本的类体系结构。

四级接口继承体系:

  1. BeanFactory 作为一个主接口不继承任何接口,暂且称为一级接口 获取 bean,是否包含bean,是否单例与原型,获取bean类型,bean别名 api
  2. AutowireCapableBeanFactory提供工厂的装配功能、HierarchicalBeanFactory提供父容器的访问功能、ListableBeanFactory容器内 bean 实例的枚举功能 3个子接口继承它,进行功能上的增强,这3个子接口称为二级接口。
  3. ConfigurableBeanFactory 称为三级接口,对二级接口 HierarchicalBeanFactory 进行了再次增强,还继承了一个外来的接口 SingletonBeanRegistry
  4. ConfigurableListableBeanFactory 是一个更强大的接口,继承了上述所有的接口,四级接口解析,修改bean定义,并初始化单例

接口隔离原则。

抽象类和实现类

  1. AbstractBeanFactory 作为一个抽象类,实现了三级接口 ConfigurableBeanFactory
  2. AbstractAutowireCapableBeanFactory 同样是抽象类,继承自 AbstractBeanFactory ,并额外实现了二级接口 AutowireCapableBeanFactory 大部分功能。
  3. DefaultListableBeanFactory 继承自 AbstractAutowireCapableBeanFactory ,实现了最强大的四级接口 ConfigurableListableBeanFactory ,并实现了一个外来接口 BeanDefinitionRegistry ,它并非抽象类。
  4. 最后是最强大的 XmlBeanFactory ,继承自 DefaultListableBeanFactory ,重写了一些功能,使自己更强大

为什么要定义这么多层次的接口?
每个接口都有适用场合,主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程,对对象的数据访问所做的限制。例如:ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个 Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为。

BeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public interface BeanFactory {

// 用来引用一个实例,或把它和工厂产生的Bean区分开
// 就是说,如果一个FactoryBean的名字为a,
// 那么,&a会得到那个Factory String FACTORY_BEAN_PREFIX = "&";
/* * 四个不同形式的getBean方法,获取实例 */
Object getBean(String name) throws BeansException;
<T> T getBean(String name, Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
// 是否存在
boolean containsBean(String name);
// 是否为单实例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 是否为原型(多实例)
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
// 名称、类型是否匹配
boolean isTypeMatch(String name, Class<?> targetType) throws NoSuchBeanDefinitionException;
// 获取类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 根据实例的名字获取实例的别名
String[] getAliases(String name);
}

BeanFactory 中只对 IOC 容器的基本行为作了定义,根本不关心 Bean 是如何定义怎样加载的,只关心工厂里得到什么产品对象,至于怎样生产这些对象,这个接口不关心。

ListableBeanFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface ListableBeanFactory extends BeanFactory {
// 对于给定的名字是否含有
boolean containsBeanDefinition(String beanName);
// 返回工厂的BeanDefinition总数
int getBeanDefinitionCount();
// 返回工厂中所有Bean的名字
String[] getBeanDefinitionNames();
// 返回对于指定类型Bean(包括子类)的所有名字
String[] getBeanNamesForType(Class<?> type);,
/**
* 返回指定类型的名字
* includeNonSingletons为false表示只取单例Bean,true则不是
* allowEagerInit为true表示立刻加载,false表示延迟加载。
* 注意:FactoryBeans都是立刻加载的。
*/
String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit);
// 根据类型(包括子类)返回指定Bean名和Bean的Map
<T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
<T> Map<String, T> getBeansOfType(Class<T> type,)throws BeansException;
// 根据注解类型,查找所有有这个注解的Bean名和Bean的Map
Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) throws BeansException;
// 根据指定Bean名和注解类型查找指定的Bean
<A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType);
}

ListableBeanFactory 3个跟BeanDefinition 有关的总体操作,包括 BeanDefinition 的总数、名字的集合、指定类型的名字的集合。

BeanDefinition 是 Spring 中非常重要的一个类,每个 BeanDefinition 实例都包含一个类在 Spring 工厂中的所有属性。

  • 两个 getBeanNamesForType 重载方法,根据指定类型(包括子类)获取其对应的所有 Bean 名字

  • 两个 getBeansOfType 重载方法,根据类型(包括子类) 返回指定 Bean 名和 Bean 的Map

  • 2个跟注解查找有关的方法,根据注解类型,查找 Bean 名和 Bean 的 Map,根据指定 Bean 名和注解类型查找指定 Bean

这个工厂的最大特点就是可以列出工厂可以生产的所有实例。工厂并不能直接生产,但是可以返回指定类型的所有实例。

HierarchicalBeanFactory

分层的Bean工厂

1
2
3
4
5
6
public interface HierarchicalBeanFactory extends BeanFactory {
// 返回本Bean工厂的父工厂
BeanFactory getParentBeanFactory();
// 本地工厂是否包含这个Bean
boolean containsLocalBean(String name);
}

第一个方法返回 Bean 工厂的父工厂,这个方法实现了工厂的分级
第二个方法判断本地工厂是否包含这个 Bean(忽略其他所有父工厂)

AutowireCapableBeanFactory

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
public interface AutowireCapableBeanFactory extends BeanFactory {
// 表明工厂没有自动装配的 Bean
int AUTOWIRE_NO = 0;
// 根据名称自动装配
int AUTOWIRE_BY_NAME = 1;
// 根据类型自动装配
int AUTOWIRE_BY_TYPE = 2;
// 根据构造方法快速装配
int AUTOWIRE_CONSTRUCTOR = 3;
// 根据指定 Class 创建一个全新的 Bean 实例
<T> T createBean(Class<T> beanClass) throws BeansException;
// 给定对象,根据注解、后处理器等,进行自动装配
void autowireBean(Object existingBean) throws BeansException;
// 根据Bean名的BeanDefinition装配这个未加工的Object,执行回调和各种后处理器。
Object configureBean(Object existingBean, String beanName) throws BeansException;

// 根据给定的类型和指定的装配策略,创建一个新的Bean实例
Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
// 与上面类似,不过稍有不同。
Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;
// 根据名称或类型自动装配
void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
throws BeansException;
// 也是自动装配
void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;
// 初始化一个 Bean...
Object initializeBean(Object existingBean, String beanName) throws BeansException;
// 初始化之前执行BeanPostProcessors
Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException;
// 初始化之后执行BeanPostProcessors
Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException;

void destroyBean(Object existingBean);
<T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;

// 分解指定的依赖
@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;
// 分解指定的依赖
@Nullable
Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;

}

5个静态不可变常量指明装配策略。8个跟自动装配有关的方法,2个执行 BeanPostProcessors 方法,2个分解指定依赖的方法。

根据定义 BeanDefinition 装配 Bean。执行前、后处理器等。

ConfigurableBeanFactory

复杂的配置Bean工厂

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
public interface ConfigurableBeanFactory extends HierarchicalBeanFactory, SingletonBeanRegistry {

String SCOPE_SINGLETON = "singleton";

String SCOPE_PROTOTYPE = "prototype";
// 搭配HierarchicalBeanFactory接口的getParentBeanFactory方法
void setParentBeanFactory(BeanFactory parentBeanFactory) throws IllegalStateException;
// 设置、返回工厂的类加载器
void setBeanClassLoader(@Nullable ClassLoader beanClassLoader);

@Nullable
ClassLoader getBeanClassLoader();
// 设置、返回一个临时的类加载器
void setTempClassLoader(@Nullable ClassLoader tempClassLoader);

@Nullable
ClassLoader getTempClassLoader();
// 设置、是否缓存元数据,如果false,那么每次请求实例,都会从类加载器重新加载(热加载)
void setCacheBeanMetadata(boolean cacheBeanMetadata);
// 是否缓存元数据
boolean isCacheBeanMetadata();
// Bean表达式分解器
void setBeanExpressionResolver(@Nullable BeanExpressionResolver resolver);

@Nullable
BeanExpressionResolver getBeanExpressionResolver();
// 设置、返回一个转换服务
void setConversionService(@Nullable ConversionService conversionService);

@Nullable
ConversionService getConversionService();
// 设置属性编辑登记员...
void addPropertyEditorRegistrar(PropertyEditorRegistrar registrar);
// 注册常用属性编辑器
void registerCustomEditor(Class<?> requiredType, Class<? extends PropertyEditor> propertyEditorClass);
// 用工厂中注册的通用的编辑器初始化指定的属性编辑注册器
void copyRegisteredEditorsTo(PropertyEditorRegistry registry);
// 设置、得到一个类型转换器
void setTypeConverter(TypeConverter typeConverter);

TypeConverter getTypeConverter();
// 增加一个嵌入式的StringValueResolver
void addEmbeddedValueResolver(StringValueResolver valueResolver);

boolean hasEmbeddedValueResolver();
// 分解指定的嵌入式的值
@Nullable
String resolveEmbeddedValue(String value);
// 设置一个Bean后处理器
void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
// 返回Bean后处理器的数量
int getBeanPostProcessorCount();
// 注册范围
void registerScope(String scopeName, Scope scope);
// 返回注册的范围名
String[] getRegisteredScopeNames();
// 返回指定的范围
@Nullable
Scope getRegisteredScope(String scopeName);
// 返回本工厂的一个安全访问上下文
AccessControlContext getAccessControlContext();
// 从其他的工厂复制 相关的所有配置
void copyConfigurationFrom(ConfigurableBeanFactory otherFactory);
// 给指定的Bean注册别名
void registerAlias(String beanName, String alias) throws BeanDefinitionStoreException;
// 根据指定的 StringValueResolver移除所有的别名
void resolveAliases(StringValueResolver valueResolver);
// 返回指定Bean合并后的Bean定义
BeanDefinition getMergedBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
// /判断指 定Bean是否为一个工厂Bean
boolean isFactoryBean(String name) throws NoSuchBeanDefinitionException;
// 设置一个Bean是 否正在创建
void setCurrentlyInCreation(String beanName, boolean inCreation);
// 返回指定Bean是否已经成功创建
boolean isCurrentlyInCreation(String beanName);
// 注册一个 依赖于指定bean的Bean
void registerDependentBean(String beanName, String dependentBeanName);
// 返回依赖于指定Bean的所欲Bean名
String[] getDependentBeans(String beanName);
// 返回指定Bean依赖的所有Bean名
String[] getDependenciesForBean(String beanName);
// 销毁指定的Bean
void destroyBean(String beanName, Object beanInstance);
// 销毁指定范围Bean
void destroyScopedBean(String beanName);
// 销毁所有单例类
void destroySingletons();
}

ConfigurableListableBeanFactory

BeanFactory的集大成者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface ConfigurableListableBeanFactory
extends ListableBeanFactory, AutowireCapableBeanFactory, ConfigurableBeanFactory {
void ignoreDependencyType(Class<?> type); // 忽略自动装配的依赖类型
void ignoreDependencyInterface(Class<?> ifc); // 忽略自动装配的接口
void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue); // 注册一个可分解的依赖
boolean isAutowireCandidate(String beanName, DependencyDescriptor descriptor)
throws NoSuchBeanDefinitionException; // 判断指定的Bean是否有资格作为自动装配的候选者
// 返回注册的Bean定义
BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
Iterator<String> getBeanNamesIterator();
void clearMetadataCache();
// 暂时冻结所有的Bean配置
void freezeConfiguration();

// 判断本工厂配置是否被冻结
boolean isConfigurationFrozen();
// 使所有的非延迟加载的单例类都实例化。
void preInstantiateSingletons() throws BeansException;
}

工厂接口 ConfigurableListableBeanFactory 同时继承了3个接口, ListableBeanFactoryAutowireCapableBeanFactoryConfigurableBeanFactory ,扩展之后,加上自有的这8个方法,这个工厂接口总共有83个方法,实在是巨大到不行了。这个工厂接口的自有方法总体上只是对父类接口功能的补 充,包含了 BeanFactory 体系目前的所有方法,可以说是接口的集大成者。

BeanDefinition

手写 IOC 框架思路


  1. 读取配置文件的 bean 信息
  2. 将 bean 信息封装到 BeanDefinition 集合对象中
  3. 根据传递过来的 beanName 参数去 BeanDefinition 集合中查找对应的 BeanDefinition 信息
  4. 根据 BeanDefinition 中的信息去创建 Bean 的实例。
    • a.根据 class 信息包括里面的 constructor-arg 通过反射进行实例化
    • b.根据 BeanDefinition 中封装的属性信息集合去挨个给对象赋值
    • c.根据 initMethod 方法区调用对象的初始化操作

如果 singletonObjects 中已经包含了我们要找的对象,就不需要再创建了。

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
public class BeanFactory {
Map<String, BeanDefination> beanDefinations = new HashMap<>;
Map<String, Object> singletonObjects = new HashMap<>();

BeanFactory() {
// 读取配置文件的 bean 信息
// 将 bean 信息封装到 BeanDefinition 对象中
/**
* 对 bean 标签解析
* class
* id
* init-method
* property 标签信息---PropertyValue 对象
* name 信息
* value 信息 value 属性---属性值、属性类型(属性赋值的时候,需要进行类型转换) TypeStringValue
* ref 属性 RuntimeBeanReference(bean 的名称) 根据 bean 的名称获取
* bean实例再赋值
*/
// 将 BeanDefinition 放入合集对象中
}

public static Object getBean(String name) {
// 1. 如果 singletonObjects 中已经包含了我们要找的对象,就不需要再创建了。
// 2. 读取配置文件的 bean 信息
// 3. 将 bean 信息封装到 BeanDefinition 集合对象中
// 4. 根据传递过来的 beanName 参数去 BeanDefinition 集合中查找对应的 BeanDefinition 信息
// 5. 根据 BeanDefinition 中的信息去创建 Bean 的实例。
// - a.根据 class 信息包括里面的 constructor-arg 通过反射进行实例化
// - b.根据 BeanDefinition 中封装的属性信息集合去挨个给对象赋值
// - c.根据 initMethod 方法区调用对象的初始化操作
}
}

实现


在阅读源码时,需要抓住主线,在手写框架时也一样,先写使用。再写实现

pom.xml中引入自己的框架

1
2
3
4
5
<dependency>
<groupId>cn.lizhaoloveit</groupId>
<artifactId>spring-framework-custom</artifactId>
<version>1.0</version>
</dependency>

bean.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<beans>
<bean id="student" class="cn.lizhaoloveit.spring.po.Student" init-method="initMethod">
<!-- String类型 -->
<property name="name" value="zengkeyan"></property>
<!-- 引用类型 -->
<property name="course" ref="course"></property>
</bean>
<!-- 该类有一个初始化方法 -->
<bean id="course" class="cn.lizhaoloveit.spring.po.Course"
init-method="init">
<!-- String类型 -->
<property name="name" value="spring"></property>
<!-- Integer类型 -->
<property name="age" value="18"></property>
</bean>
</beans>
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
public class Student {
private String name;
private Course course;
public void initMethod() {
System.out.println("初始化方法");
}
public void destroyMethod() {
System.out.println("销毁方法");
}
}
public class Course {
private String name;
private Integer age;
public void init() {
System.out.println("我是对象初始化方法");
}
}
@Test
public void test() {
String location = "classpath:beans.xml";
// 创建工厂
BeanFactory beanFactory = new DefaultListableBeanFactory(location);
// 从工厂中获取指定对象
Student student = beanFactory.getBeans(Student.class);
// 从工厂中获取指定对象
Student student1 = (Student) beanFactory.getBeans("student");
// 测试对象是否可用
System.out.println(student);
System.out.println(student1);
}
// 运行结果如下:
我是对象初始化方法
初始化方法
初始化方法
Student(name=zengkeyan, course=Course(name=spring, age=18))
Student(name=zengkeyan, course=Course(name=spring, age=18))

初始化工厂 beanFactory


根据源码分析,先定义顶层逻辑:

BeanFactory

1
2
3
4
public interface BeanFactory {
Object getBeans(String beanName);
<T> T getBeans(Class<T> clazz);
}

根据分析,为了避免循环引用导致对象创建失败,我们需要先将xml中的文本中的信息封装在BeanDefinition类中。

1
2
3
4
5
6
7
8
9
10
11
12
13
public class BeanDefinition {
private String beanName; // bean的标识(可能是id,也可能是根据类型命名)
private String beanClassName; // bean的Class权限名
private String initMethod; // 初始化方法
private List<PropertyValue> propertyValues = new ArrayList<>(); // bean 中包含哪些属性
public BeanDefinition(String clzName, String beanName) {
this.beanClassName = clzName;
this.beanName = beanName;
}
public void addPropertyValue(PropertyValue propertyValue) {
propertyValues.add(propertyValue);
}
}

抽象类:AbstractBeanFactory,完成其他实现方便扩展。拆分接口,使其可以有更多的功能拆分,结构更明确。

1
2
3
4
5
6
7
8
9
10
11
12
public abstract class AbstractBeanFactory implements BeanFactory {
@Override
public <T> T getBeans(Class<T> clazz) {
return null;
}
@Override
public Object getBeans(String beanName) {
return null;
}
public abstract void registerBeanDefinition(String beanName, BeanDefinition beanDefinition);
public abstract void registerBeanDefinitionClz(String simpleName, BeanDefinition beanDefinition);
}

new DefaultListableBeanFactory(location);根据 location 初始化beanFactory。

1
2
3
4
5
6
7
8
9
10
11
public DefaultListableBeanFactory(String location) {
//注册资源类(从哪里获取资源)
registResource();
// 注册类型转换器
registConverters();
// 不清楚 location 字符串到底代表的类路径下的 xml 或者是 绝对路径下的 xml 或者网络中的 xml
Resource resource = getResource(location);
// 获取了资源对象,根据资源对象创建 BeanDefinitions,此时需要个解析器
XmlBeanDefinitionParser parser = new XmlBeanDefinitionParser();
parser.loadBeanDefinations(this, resource);
}

Resource 接口用于根据不同的方式来获取资源

1
2
3
4
public interface Resource {
boolean isCanRead(String location);
InputStream getInputStream();
}

实现类 ClassPathResource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ClassPathResource implements Resource {
private String location;
@Override
public boolean isCanRead(String location) {
if (location == null || "".equals(location)) {
return false;
}
if (location.startsWith("classpath:")) {
this.location = location;
return true;
}
return false;
}
@Override
public InputStream getInputStream() {
if (location == null || "".equals(location)) return null;
String replace = location.replace("classpath:", "");
return this.getClass().getClassLoader().getResourceAsStream(replace);
}
}

将资源实现类,加入 DefaultListableBeanFactory 的资源列表,如果有更多途经,可以添加更多的类,本着对修改关闭,对扩展开放的开闭原则。

1
2
3
private void registResource() {
resources.add(new ClassPathResource());
}

拿到资源流后,根据资源创建 BeanDefinitions,此时需要一个解析器,将xml中的内容解析为 BeanDefinition 对象。

1
2
3
4
5
6
7
8
9
public class XmlBeanDefinitionParser {
public void loadBeanDefinations(DefaultListableBeanFactory beanFactory, Resource resource) {
// 读取文件的配置信息
InputStream inputStream = resource.getInputStream();
Document document = DocumentReader.createDocument(inputStream);
XmlBeanDefinitionDocumentReader reader = new XmlBeanDefinitionDocumentReader(beanFactory);
reader.loadBeanDefinitions(document.getRootElement());
}
}

在每一处有可能有扩展的地方,使用面向对象的思想,XmlBeanDefinitionDocumentReader专门解析 Document。

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
public class XmlBeanDefinitionDocumentReader {
private DefaultListableBeanFactory beanFactory;
public XmlBeanDefinitionDocumentReader(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public void loadBeanDefinitions(Element rootElement) {
List<Element> elements = rootElement.elements();
for (Element element : elements) {
// 获取标签名称
String name = element.getName();
// 判断是否为 bean标签
if (name.equals("bean")) {
parseBeansElement(element);
} else {
parseCustomElement(element);
}
}
// 2.将bean信息封装到BeanDefinition对象中
// 对bean标签解析解析
// class信息
// id信息
// init-method信息
// property标签信息----PropertyValue对象(name和value)
// name信息
// value信息
// value属性---属性值、属性类型(属性赋值的时候,需要进行类型转换)TypedStringValue
// ref属性---RuntimeBeanReference(bean的名称)---根据bean的名称获取bean的实例,将获取到的实例赋值该对象
// 3.再将BeanDefinition放入beanDefinations集合对象中
}

/**
* bean element
*
* @param element beanElement
*/
private void parseBeansElement(Element element) {
if (element == null) return;
try {
// 获取 id class init-method
String id = element.attributeValue("id");
String name = element.attributeValue("name");
String clzName = element.attributeValue("class");
Class<?> clzType = Class.forName(clzName);
String initMethod = element.attributeValue("init-method");
// 保存到 BeanDefinition 类中
String beanName = id == null ? name : id;
beanName = beanName == null ? clzType.getSimpleName() : beanName;
BeanDefinition beanDefinition = new BeanDefinition(clzName, beanName);
beanDefinition.setInitMethod(initMethod);
// 获取 property 标签
List<Element> propertyElements = element.elements();
for (Element propertyElement : propertyElements) {
parsePropertyElement(beanDefinition, propertyElement);
}
// 注册 BeanDefinition 信息
registerBeanDefinition(beanName, beanDefinition);
registerBeanDefinitionClass(clzType.getSimpleName(), beanDefinition);

} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private void parsePropertyElement(BeanDefinition beanDefinition, Element propertyElement) {
if (propertyElement == null) return;
// 获取 name 属性
String name = propertyElement.attributeValue("name");
String value = propertyElement.attributeValue("value");
String ref = propertyElement.attributeValue("ref");
if (value != null && !value.equals("") && ref != null && !ref.equals("")) return;

PropertyValue propertyValue = null;
if (value != null && !value.equals("")) {
// 不是引用类型,因为 xml 中的 value 是String 类型,而成员变量的类型可能是各种各样的,所以要存储类型
Class<?> classType = ReflectUtils.getTypeByFieldName(beanDefinition.getBeanClassName(), name);
TypeStringValue typeStringValue = new TypeStringValue(value, classType);
propertyValue = new PropertyValue(name, typeStringValue);
beanDefinition.addPropertyValue(propertyValue);
} else if (ref != null && !ref.equals("")) {
RuntimeBeanReference reference = new RuntimeBeanReference(ref);
propertyValue = new PropertyValue(name, reference);
beanDefinition.addPropertyValue(propertyValue);
} else return;
}
private void parseCustomElement(Element element) {
}
private void registerBeanDefinitionClass(String simpleName, BeanDefinition beanDefinition) {
this.beanFactory.registerBeanDefinitionClz(simpleName, beanDefinition);
}
private void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
this.beanFactory.registerBeanDefinition(beanName, beanDefinition);
}
}
```
解析的过程实际上就是把xml中的Bean标签中的内容填给 BeanDefinition 对象。
值得一说的是 `property` 标签的解析,因为 property 可能有引用类型和数值类型的值。因此在赋值时,需要将两种类型分别创建对象

```java
public class PropertyValue {
private String name;
private Object value;
}
// value 有可能是数值或者引用类型
public class TypeStringValue {
private String value;
private Class<?> classType;
}
// 数值类型也有很多类型。
public class RuntimeBeanReference {
private String ref;
}
// 引用类型实际上只需要从容器中寻找对应的值就行了。

以上,初始化的过程就完结了。

取值


取值的过程实际上就是把 BeanDefinition 中的信息通过反射创建对象。

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
@Override
public Object getBeans(String beanName) {
Object instance = singletonObjects.get(beanName);
if (instance != null) return instance;
// 2.如果singletonObjects中已经没有包含我们要找的对象,那么根据传递过来的beanName参数去BeanDefinition集合中查找对应的BeanDefinition信息
BeanDefinition beanDefinition = getBeanDefinitionIds().get(beanName);
String beanClassName = beanDefinition.getBeanClassName();
instance = createBeanInstance(beanClassName, null);
setProperty(instance, beanDefinition);
initBean(instance, beanDefinition);
singletonObjects.put(beanName, instance);
return instance;
}

@Override
public <T> T getBeans(Class<T> clazz) {
// 优化方案
// 给对象起个名,在xml配置文件中,建立名称和对象的映射关系
// 1.如果singletonObjects中已经包含了我们要找的对象,就不需要再创建了。
String clazzSimpleName = clazz.getSimpleName();
T instance = (T) singletonObjects.get(clazzSimpleName);
if (instance != null) return instance;
// 2.如果singletonObjects中已经没有包含我们要找的对象,那么根据传递过来的beanName参数去BeanDefinition集合中查找对应的BeanDefinition信息
BeanDefinition beanDefinition = getBeanDefinitionClzs().get(clazzSimpleName);
// 3.根据BeanDefinition中的信息去创建Bean的实例。
String beanClassName = beanDefinition.getBeanClassName();
// a)根据class信息包括里面的constructor-arg通过反射进行实例化
instance = (T) createBeanInstance(beanClassName, null);
// b)根据BeanDefinition中封装的属性信息集合去挨个给对象赋值。
// 设置参数
// 类型转换
// 反射赋值
setProperty(instance, beanDefinition);
// c)根据initMethod方法去调用对象的初始化操作
initBean(instance, beanDefinition);
singletonObjects.put(clazzSimpleName, instance);
return instance;
}

private <T> void initBean(T instance, BeanDefinition beanDefinition) {
String initMethod = beanDefinition.getInitMethod();
if (initMethod == null || initMethod.equals("")) return;
ReflectUtils.invokeMethod(instance, initMethod, null);
}

private <T> void setProperty(T instance, BeanDefinition beanDefinition) {
List<PropertyValue> propertyValues = beanDefinition.getPropertyValues();
for (PropertyValue propertyValue : propertyValues) {
String name = propertyValue.getName();
Object value = propertyValue.getValue();

Object trueValue = null;
if (value instanceof TypeStringValue) {
TypeStringValue typeStringValue = (TypeStringValue) value;
String stringValue = typeStringValue.getValue();
Class<?> clazz = typeStringValue.getClassType();
// 使用类型转换器进行转换
for (TypeConverter typeConverter : typeConverters) {
if (typeConverter.isType(clazz)) {
trueValue = typeConverter.convert(stringValue);
}
}
} else if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference reference = (RuntimeBeanReference) value;
String ref = reference.getRef();
trueValue = getBeans(ref);
}
// 值类型转换完后 使用反射赋值
ReflectUtils.setProperty(instance, name, trueValue);
}
}
private Object createBeanInstance(String beanClassName, Object... args) {
return ReflectUtils.createObject(beanClassName, args);
}
```

需要说明的是,在给属性 property 赋值时,如果值类型为数据类型,则需要进行类型转换,将字符串转换成对应的数据类型。这里就需要用到类型转换器,`TypeConverter` 的作用就是识别类型并且将字符串类型的数据转换为其他数据类型。

```java
public interface TypeConverter {
boolean isType(Class<?> clazz);
Object convert(String source);
}
public class IntegerTypeConverter implements TypeConverter {
@Override
public Integer convert(String source) {
return Integer.parseInt(source);
}
@Override
public boolean isType(Class<?> clazz) {
return clazz == Integer.class;
}
}
public class StringTypeConverter implements TypeConverter {
@Override
public boolean isType(Class<?> clazz) {
return clazz == String.class;
}
@Override
public String convert(String source) {
return source;
}
}

以上代码还用到了两个工具类,将反射的操作进行了封装,封装了 dom4j 的操作

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
public class DocumentReader {
public static Document createDocument(InputStream inputStream) {
Document document = null;
SAXReader reader = new SAXReader();
try {
document = reader.read(inputStream);
} catch (DocumentException e) {
e.printStackTrace();
}
return document;
}
}

public class ReflectUtils {
public static Object createObject(String beanClassName, Object... args) {
try {
Class<?> clazz = Class.forName(beanClassName);
Constructor<?> constructor = clazz.getConstructor();
// 默认调用无参构造进行对象的创建
return constructor.newInstance(args);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void setProperty(Object beanInstance, String name, Object value) {
try {
Class<?> clazz = beanInstance.getClass();
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
field.set(beanInstance, value);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Class<?> getTypeByFieldName(String beanClassName, String name) {
try {
Class<?> clazz = Class.forName(beanClassName);
Field field = clazz.getDeclaredField(name);
return field.getType();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static void invokeMethod(Object beanInstance, String initMethod, Object... args) {
try {
Class<?> clazz = beanInstance.getClass();
Method method = clazz.getDeclaredMethod(initMethod);
method.setAccessible(true);
method.invoke(beanInstance, args);
} catch (Exception e) {
e.printStackTrace();
}
}
}

至此就是想了 spring 中的 IOC 功能。

SpringIoc源码


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
// 完成IoC容器的创建及初始化工作
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
// STEP 1: 刷新预处理
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
// STEP 2:
// a) 创建IoC容器(DefaultListableBeanFactory)
// b) 加载解析XML文件(最终存储到Document对象中)
// c) 读取Document对象,并完成BeanDefinition的加载和注册工作
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
// STEP 3: 对IoC容器进行一些预处理(设置一些公共属性)
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
// STEP 4:
postProcessBeanFactory(beanFactory);

// Invoke factory processors registered as beans in the context.
// STEP 5: 调用BeanFactoryPostProcessor后置处理器对BeanDefinition处理
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
// STEP 6: 注册BeanPostProcessor后置处理器
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
// STEP 7: 初始化一些消息源(比如处理国际化的i18n等消息源)
initMessageSource();

// Initialize event multicaster for this context.
// STEP 8: 初始化应用事件广播器
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
// STEP 9: 初始化一些特殊的bean
onRefresh();

// Check for listener beans and register them.
// STEP 10: 注册一些监听器
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// STEP 11: 实例化剩余的单例bean(非懒加载方式)
// 注意事项:Bean的IoC、DI和AOP都是发生在此步骤
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
// STEP 12: 完成刷新时,需要发布对应的事件
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
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();
}
}
}

AbstractApplicationContext#refresh: 刷新 spring 容器(删除原有容器,创建新容器)

  • refresh 里面12个步骤,和IoC相关的是:step2 和 step11,在初始化时一次性创建所有单例
    • obtainFreshBeanFactory
      • refreshBeanFactory() 创建 BeanFactory 对象(DefaultListableBeanFactory) 加载 bean信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected final void refreshBeanFactory() throws BeansException {
// 如果之前有IoC容器,则销毁
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建IoC容器,也就是DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 设置工厂的属性:是否允许BeanDefinition覆盖和是否允许循环依赖
customizeBeanFactory(beanFactory);
// 调用载入BeanDefinition的方法,在当前类中只定义了抽象的loadBeanDefinitions方法,具体的实现调用子类容器
loadBeanDefinitions(beanFactory);//钩子方法
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

这里用到里模板方法,具体的加载方法在子类中实现。将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中。

从子类 AbstractRefreshableApplicationContext.java 开始就加载 beanDefinition。
XmlBeanDefinitionReader#loadBeanDefinitions:通过 resource 定位 xml 资源,进行加载读取。

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
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}

Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
try {
// 将资源文件转为InputStream的IO流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
// 从InputStream中得到XML的解析源
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 这里是具体的读取过程
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"IOException parsing XML document from " + encodedResource.getResource(), ex);
}
finally {
currentResources.remove(encodedResource);
if (currentResources.isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
}

doLoadBeanDefinitions 方法做具体工作,之前的步骤在堆 resource 进行编码工作。然后调用了下面的方法

  • registerBeanDefinitions(document, resource)

DefaultBeanDefinitionDocumentReader#registerBeanDefinition 中 调用doRegisterBeanDefinitions注册。

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
protected void doRegisterBeanDefinitions(Element root) {
// Any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.

// 这里使用了委托模式,将具体的BeanDefinition解析工作交给了BeanDefinitionParserDelegate去完成
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);

// 判断该根标签是否包含http://www.springframework.org/schema/beans默认命名空间
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (logger.isInfoEnabled()) {
logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
"] not matching: " + getReaderContext().getResource());
}
return;
}
}
}
// 在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性
preProcessXml(root);
// 委托给BeanDefinitionParserDelegate,从Document的根元素开始进行BeanDefinition的解析
parseBeanDefinitions(root, this.delegate);
// 在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性
postProcessXml(root);

this.delegate = parent;
}

parseBeanDefinitions 从根标签开始解析。然后 parseDefaultElement 解析 bean 标签等默认子标签。

processBeanDefinition 解析Bean标签,初始化。还有其他子标签。分情况解析。

BeanDefinitionParserDelegate#parseBeanDefinitionElement 委托 BeanDefinitionParserDelegate 解析。创建 beanDefinition 信息。

循环依赖问题


Spring 中循环依赖的场景

  • 构造器的循环依赖,无法解决,只能将其转变为setter的循环依赖。

解决方案:通过递归方法找出当前 Bean 所依赖的 Bean,然后提前缓存放入cache中,通过提前暴露,exposedObject 用于返回提前暴露的 bean。

Spring 先将 bean 对象实例化(依赖无参构造器),再设置对象属性。Spring 先用构造器实例化 Bean 对象,将实例化结束的对象放到一个 Map 中,并且 Spring 提供获取这个未设置属性的对象的引用方法。如果 A 对象 引用B 对象,会直接从 Map 中获取 B 对象。就不会出现循环问题了。

三级缓存分别指:

  • singletonFactories
  • earlySingletonObjects : 提前曝光的的单例对象的 Cache 用于检测循环引用,与 singletonFactories 互斥
  • singletonObject 单例对象的 Cache。

在创建 bean 的时候,首先想到的是从 cache 中获取这个单例的 bean,如果对象为空或者正在创建中,(如果A在创建中依赖了B,就得先创建B,A就在处于创建中状态),Spring 首先从一级缓存 singletonObjects 中获取,如果获取不到,并且对象正在创建,就再从二级缓存 earlySingletonObjects 中获取,如果还是取不到,则从 三级缓存 singletonFactory.getObject 获取,如果取到了,就将该对象从三级缓存中删除,移入二级缓存中

1
this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName);

创建对象三步:

  1. 实例化对象,将当前的 beanName 和 一个 ObjectFactory 存储到三级缓存中,ObjectFactory 中的工作就是将第一步创建的空对象提前暴露
  2. 填充属性,填充属性B 需要先创建 B 对象,创建B对象,又需要A对象的属性注入(A 对象不会重新创建,而是从一二三级缓存中去取A对象,此时A对象在三级缓存中)
  3. 初始化对象。

总结


ClassPathXmlApplicationContext:可能是 ClassPath 也可能是 Context
AbstractApplicationContext
AbstractRefreshableApplicationContext
AbstractXmlApplicationContext : 可能是 Xml 也可能是注解,

不同的部分用不同的面向对象,相同的部分用共同对象,比如不管是从 Context 中还是 ClassPath 中创建 Context 创建时的部分是一样的。

AbstractBeanDefinitionReader
XmlBeanDefinitionReader

DefaultBeanDefinitionReader

BeanDefinitionParserDelegate 具体解析 Bean 标签成 BeanDefinition 对象是由该对象完成。

为什么 XmlBeanDefinitionReader 要继承 AbstractBeanDefinitionReader?

因为 AbstractXmlApplicationContext 想找阅读器,肯定是找一个通用的阅读器。具体阅读功能的实现是根据不同的情况来由子类实现。

文章作者: Ammar
文章链接: http://lizhaoloveit.cn/2020/04/01/Spring%E6%A1%86%E6%9E%B6IOC%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Ammar's Blog
打赏
  • 微信
  • 支付宝

评论