spring IoC源码解析

简述

陆陆续续看spring IoC与AOP大概一个多月,今天整理下笔记,方便以后的复习。

只要是做Java web的基本都很熟悉spring,提到spring,必说其核心的两个概念:IoC与AOP,实际只要看过源码的小伙伴,肯定知道spring的AOP是基于IoC做的,而且spring的AOP也只能处理自己管理的bean,针对的是方法级的切面。

IoC

谈到IoC(Inversion of Control),”控制反转“,面向对象的设计思想之一。
解决的问题:利用依赖注入的方式,实现对象之间的解耦。

了解IoC,我们从几个方面进行剖析:

  • 为什么引入IoC
  • spring如何实现的IoC
  • Bean的解析,注册
  • Bean的实例化

为什么引入IoC

什么是IoC

控制反转,是面向对象的一种设计原则,减少代码之间的耦合,还有另外一种叫法”依赖注入DI“。

使用IoC的前后差别

IoC提供的策略:你要的时候,我给你送来。
控制反转遵循好莱坞原则:Don’t call us, we will call you.

IoC解决什么问题

1.业务对象的构建管理
2.业务对象间的依赖绑定

IoC的实现原理

简单一句话总结:通过Java反射,即set赋值

spring如何实现IoC

最核心:Bean
理解bean,必须理解三个核心接口:

BeanFactory
IoC容器的接口定义。
IoC比作水桶,那BeanFactory就是定义水桶的基本功能,能装水,有把手。

ApplicationContext
BeanFactory是最基本的水桶,而ApplicationContext是扩展后的水桶,它通过继承 MessageSource,ResourceLoader,ApplicationEventPublisher 接口,在BeanFactory 简单IOC容器的基础上添加了许多对高级容器的支持。

BeanDefinition
实现控制反转的核心数据结构。每个bean都有自己的信息,各个属性,类名,类型,是否单例,这些都是bean的信息。

题外话

陆续看一些redis,mysql核心原理都在于对模型的抽象,即数据结构。

大家可以打开spring的源码重点看下这三个接口,对他们有个大概的了解,因为后续的源码解析,会用到这三个。

Bean的解析与注册

通过一个简单的入口进行核心流程。
配置条件:简单的bean,spring配置的xml,启动类

Person

1
2
3
4
5
6
public class Person {

private String name;

private String age;
}

spring.xml

1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="person" class="com.xx.Person">
<property name="age" value="yy"/>
<property name="name" value="xx"/>
</bean>
</beans>

启动类

1
2
3
4
public static void main(String[] args) {
ApplicationContext ctx = new FileSystemXmlApplicationContext("classpath:spring.xml");
((Person) ctx.getBean("person"));
}

一切就绪,准备开始进行spring源码的核心:

AbstractApplicationContext

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
/**
*
* 1. 构建Be按Factory,以便产生所需要的bean定义实例
* 2. 注册可能感兴趣的事件
* 3. 创建bean 实例对象
* 4. 触发被监听的事件
*
*/
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// 创建bean工厂,根据配置文件解析bean及注册
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

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

// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);

// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// 实例化所以(non-lazy-init) 单例.
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
destroyBeans();
cancelRefresh(ex);
throw ex;
}

finally {
resetCommonCaches();
}
}
}

xml bean的解析及注册就在obtaionFreshBeanFactory();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
// 看到核心数据结构 BeanDefination
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

然后交给了AbstractXmlApplicationContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

initBeanDefinitionReader(beanDefinitionReader);
// 进行bean的解析
loadBeanDefinitions(beanDefinitionReader);
}

然后交给了 XmlBeanDefinitionReader进行bean的解析。真正的解析方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
// 解析成Document
Document doc = doLoadDocument(inputSource, resource);
// 从Document 解析bean,然后注册
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (SAXParseException ex) {
...
}
}

从registerBeanDefinitions跳到DefaultBeanDefinitionDocumentReader
核心逻辑在parseBeanDefinitions(root, this.delegate)

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
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);

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;
}
}
}

preProcessXml(root);
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);

this.delegate = parent;
}

然后执行parseDefaultElement(ele, delgate),大家可以看到熟悉的bean标签解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
// bean标签解析
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}

在processBeanDefinition()方法
首先创建一个BeanDefinitionHolder调用BeanDefinitionReaderUtils.registerBeanDefinition方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// Register the final decorated instance.
// 实际注册就是一个hashmap,进行put注册
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// Send registration event.
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

那beanDefinition是什么时候创建的呢?
在delegate.parseBeanDefinitionElement()里的parseBeanDefinitionElement()

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
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
String id = ele.getAttribute(ID_ATTRIBUTE);
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);

List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}

String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("No XML 'id' specified - using '" + beanName +
"' as bean name and " + aliases + " as aliases");
}
}

if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}

// 创建BeanDefinition(解析 id,class etc)
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
beanName = BeanDefinitionReaderUtils.generateBeanName(
beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
// Register an alias for the plain bean class name, if still possible,
// if the generator returned the class name plus a suffix.
// This is expected for Spring 1.2/2.0 backwards compatibility.
String beanClassName = beanDefinition.getBeanClassName();
if (beanClassName != null &&
beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
!this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
aliases.add(beanClassName);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Neither XML 'id' nor 'name' specified - " +
"using generated bean name [" + beanName + "]");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}

return null;
}

到这一步,bean工厂创建完成,但并未实例化。

bean的实例化

实例化过程图

源码分析就是三步
1.实例化bean(BeanUtils.instantiateClass(constructorToUse))
2.设置属性包括依赖及设值 (populateBean(…))
3.扩展的aware及前置,初始化方法(afterPropertiesSet 、 init-method),后置

还记的refresh()的那条语句嘛?

1
2
// 实例化所有的(non-lazy-init)单例
finishBeanFactoryInitialization(beanFactory);

1.实例化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
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}

@Override
public Object instantiate(RootBeanDefinition bd, String beanName, BeanFactory owner) {
// Don't override the class with CGLIB if no overrides.
if (bd.getMethodOverrides().isEmpty()) {
Constructor<?> constructorToUse;
synchronized (bd.constructorArgumentLock) {
constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
if (constructorToUse == null) {
final Class<?> clazz = bd.getBeanClass();
if (clazz.isInterface()) {
throw new BeanInstantiationException(clazz, "Specified class is an interface");
}
try {
if (System.getSecurityManager() != null) {
constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor<?>>() {
@Override
public Constructor<?> run() throws Exception {
return clazz.getDeclaredConstructor((Class[]) null);
}
});
}
else {
constructorToUse = clazz.getDeclaredConstructor((Class[]) null);
}
bd.resolvedConstructorOrFactoryMethod = constructorToUse;
}
catch (Throwable ex) {
throw new BeanInstantiationException(clazz, "No default constructor found", ex);
}
}
}
// 核心点
return BeanUtils.instantiateClass(constructorToUse);
}
else {
// Must generate CGLIB subclass.
return instantiateWithMethodInjection(bd, beanName, owner);
}
}

public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
Assert.notNull(ctor, "Constructor must not be null");
try {
ReflectionUtils.makeAccessible(ctor);
return ctor.newInstance(args);
}
...
}

2.属性装载

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
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();

if (bw == null) {
if (!pvs.isEmpty()) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
}
else {
// Skip property population phase for null instance.
return;
}
}

// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;

if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}

if (!continueWithPropertyPopulation) {
return;
}

// 进行依赖注入 类型注入和名字注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}

// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}

pvs = newPvs;
}

boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

if (hasInstAwareBpps || needsDepCheck) {
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 详细的设置值在这里
applyPropertyValues(beanName, mbd, bw, pvs);
}

3.扩展的处理

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
/**
* @see BeanNameAware
* @see BeanClassLoaderAware
* @see BeanFactoryAware
* @see #applyBeanPostProcessorsBeforeInitialization
* @see #invokeInitMethods
* @see #applyBeanPostProcessorsAfterInitialization
*/
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}

if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

到此bean的实例化结束。

IoC整个过程完毕:解析,注册,实例化。

总结

通过一个简单的demo,从xml的解析bean并注册,以及最后的实例化。可以看到spring的封装。光解析就分了好多种,例如:DocumentDefinitionReader,XmlDefinitionReader,etc良好的设计代表了优秀的扩展力。实际解析最重要的核心就是BeanDefinition的构建,解析完注册到工厂,实例化就是通过反射进行实例化,并通过beanDefinition的PropertyValues进行实例的注入(BeanFactory.getBean()),完成了整个流程,而且在实例化最后还进行扩展接口的调用,为后续开发者使用spring实现bean其他功能进行扩展。

IoC容器的大致流程:

  1. 资源的定位

  2. bean的解析,BeanFactory的构建,以及bean的注册

  3. bean的实例化

如果有兴趣,也可以反着来,直接写个Person的构造,然后把断点打在上面,看下整个程序的调用栈。

参考文献

Spring IOC 容器源码分析
深入理解 Spring 之源码剖析IOC
Spring源码深度解析(第2版)
Spring揭秘

0%