Spring IOC:实现原理

简介:介绍Spring IOC 的实现原理以及IOC容器的启动流程。

关键词:Spring IOC;IOC原理;IOC源码;IOC启动;

控制反转(IoC)

在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。

但在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里的,其大致步骤如下。

  1. 开发人员通过 XML 配置文件、注解、Java 配置类等方式,对 Java 对象进行定义,例如在 XML 配置文件中使用 标签、在 Java 类上使用 @Component 注解等。
  2. Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IoC 容器创建并管理的对象被称为 Spring Bean。
  3. 当我们想要使用某个 Bean 时,可以直接从 IoC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。

IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了“主从换位”的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象(Bean)。

这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。

IOC有一个专门的容器来创建这些对象,由IOC容器来控制对象的创建,依赖对象也是容器帮忙查找创建并进行注入,对象只是被动的接受,依赖对象的获取被反转了。它还有一个更加形象的名字叫 依赖注入。

依赖注入方式:

  • 接口注入
  • setter
  • 构造器注入

IOC容器的设计与实现有两种:BeanFactoryApplicationContext

  • 实现了BeanFactory接口的简单容器系列,只是实现了容器最基本的功能。
  • Applic ationContext应用上下文,作为容器的高级形态存在。除了具有基本的功能外,还增加了许多面向框架的特性,同时对应用环境做了许多适配。

BeanFactory

BeanFactory为IOC容器具体实现指定了基本的规范,它有三个子类,ListableBeanFactory、HierarchicalBeanFactory和AutowireCapableBeanFactory接口。但是它们最终生成了一个默认的实现类DefaultListableBeanFactory。类的继承关系如下:

img

BeanFactory接口中的方法:

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 BeanFactory {
//通过使用转义符“&”,来区分BeanFactory产生的对象和BeanFactory本身
String FACTORY_BEAN_PREFIX = "&";
//根据Bean的名字获取Bean的实例
Object getBean(String var1) throws BeansException;
//根据Bean的名字和Class类型来获取实例,增加了类型安全验证
<T> T getBean(String var1, Class<T> var2) throws BeansException;
//根据Class类型来获取实例
<T> T getBean(Class<T> var1) throws BeansException;
//返回实例
Object getBean(String var1, Object... var2) throws BeansException;
//是否包含指定的实例
boolean containsBean(String var1);
//是否单例
boolean isSingleton(String var1) throws NoSuchBeanDefinitionException;
//是否是原型
boolean isPrototype(String var1) throws NoSuchBeanDefinitionException;
//类型是否匹配
boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException;
//返回指定实例名的类型
Class<?> getType(String var1) throws NoSuchBeanDefinitionException;
//返回别名
String[] getAliases(String var1);
}

BeanFactory并不关心bean是如何定义、怎样被加载。当我们需要bean的时候,直接来取就可以了。对于工厂来说,我只需要关心有没有产品,对于产品是怎么产生,怎么制作的,那是工人干的事,工厂并不关心。定义的都是最核心的接口,如getBean()从容器中获取实例。

ApplicationContext

ApplicationContext是Spring提供的一个高级的IOC容器,与BeanFactory的区别是,BeanFactory提供了容器最基本的功能,而ApplicationContext除了提供基本IOC容器的功能外,还能为用户提供更丰富的功能:

  • 支持信息源,可以实现国际化
  • 访问资源
  • 支持应用事件
  • ApplicationContext中提供的附加服务

可以认为ApplicationContext 是 BeanFactory的扩展,在使用时,我们往往是直接与ApplicationContext 打交道。

ApplicationContext的继承关系:

img

  • 在BeanFactory中,从BeanFactory到HierarchicalBeanFactory,再到ConfigurableBeanFactory,是一个条主要的设计路径。 BeanFactory中定义了基本的IOC容器规范,在HierarchicalBeanFactory接口中增加了getparantBeanFactory()的接口功能,使BeanFactory具备了双亲IOC容器的管理功能,在ConfigurableBeanFactory主要定义了一些对BeanFactory的配置功能

  • 在ApplicationContext中,从BeanFactory到ListableBeanFactory,再到ApplicationContext,再到常用的WebApplicationContext或者ConfigurableApplicationContext接口。在BeanFactory简单接口的基础上增加了对高级容器的特性支持。

BeanDefinition

SpringIOC容器帮我们管理了各种bean对象及其相互依赖的关系,依赖关系是使用BeanDefinition来保存的:

img

Spring关于Bean的装配,有下面三种方式:

  • 在XML中进行显示配置
  • 在java中进行显示配置
  • 隐式的bean发现机制和自动装配

Bean的解析非常的复杂,功能被分的很细,需要扩展的地方也很多,必须保证有足够的灵活性,下面看一下基于xml配置文件解析的继承体系:

img

IOC容器的初始化

IOC容器的初始化包括:BeanDefinition的Resouce定位,BeanDefinition的载入和注册三个基本的过程。需要注意的是Spring把上面过程进行了分离,并使用了不同的模块来完成,定位使用了ResourceLoader,解析使用了BeanDefinitionReader等。这样设计的目的可以让用户对这三个过程进行裁剪和扩展,定义出适合自己的IOC容器初始化过程。

下面来看一下两种IOC容器的创建过程,BeanFactory以XmlBeanFactory为例,ApplicationContext 以 FileSystemXmlApplicationContext为例

XmlBeanFactroy

XmlBeanFactory的源码定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class XmlBeanFactory extends DefaultListableBeanFactory {
//定义一个BeanDefinitionReader阅读器
private final XmlBeanDefinitionReader reader;
//构造方法,需要传入Resource,资源的定位
public XmlBeanFactory(Resource resource) throws BeansException {
this(resource, (BeanFactory)null);
}
//构造方法重载,需要传入Resource,和父容器,此方法完成了读取器的初始化操作
public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
super(parentBeanFactory);
this.reader = new XmlBeanDefinitionReader(this);
this.reader.loadBeanDefinitions(resource);
}
}

通过阅读XmlBeanFactory的源码可以看出,XmlBeanFactory继承自DefaultListableBeanFactory类。而DefaultListableBeanFactory类包含了基本IOC容器所具有的重要功能。那BeanDefinition的信息来源自哪,如何定位? 定位之后又如何读取解析呢?对于信息来源的定位封装成Spring中的Resource类来给出,解析是它的内部定义了一个XmlBeanDefinitionReader对象,有了这个对象,就有了处理xml文件的能力。参考XmlBeanFactory的实现,我们手动来模拟一下XmlBeanFactory的实现过程

1
2
3
4
5
6
7
8
//首先进行BeanDefinition资源文件的定位,封装为Source的子类
ClassPathResource res = new ClassPathResource("beans.xml");
//创建基本的IOC容器
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//创建文件读取器,并进行回调设置。
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//资源加载解析
reader.loadBeanDefinitions(res);

通过上面的代码,总结一下IOC容器的使用步骤:

  • 创建IOC抽象资源,这个抽象资源包含了BeanDefinition的定义信息
  • 创建一个BeanFactory
  • 创建一个BeanDefinition的读取器,通过一个回调配置给BeanFactory
  • 从定义好的抽象资源中读取配置信息。完成载入和注册的定义后,IOC容器就建立了起来了。

FileSystemXmlApplicationContext

先来看一下FileSystemXmlApplicationContext的继承关系:

img

通过上面的继承关系,可以发现它的基类AbstractXmlApplicationContext中已经实现了主要的功能。

在看一下这个类的源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {

//构造方法重载,省略其他的构造方法
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if(refresh) {
this.refresh();
}
}
//通过一个FileSystemResource来得到一个在文件系统中定位的BeanDefinition
protected Resource getResourceByPath(String path) {
if(path != null && path.startsWith("/")) {
path = path.substring(1);
}
return new FileSystemResource(path);
}
}

除了构造方法和getResourceByPath外,并没有其他的方法。也就说它只是实现了和它自身设计相关的两个功能。该类的调用方式:

1
ApplicationContext context =new FileSystemXmlApplicationContext(xmlPath);

上面调用了参数是字符串的构造函数,但是,对构造函数的调用最终都会转到下面的方法来执行,refresh方法启动了整个容器的初始化流程:

1
2
3
4
5
6
7
public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if(refresh) {
this.refresh();
}
}

可以发现,super(parent)这个方法最终是由其基类(AbstractApplicationContext)来执行,执行了AbstractApplicationContext的无参构造方法和setParent()方法。其代码如下,省略了静态代码块的定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//FileSystemXmlApplicationContext调用父类构造方法就是该方法
public AbstractApplicationContext(ApplicationContext parent) {
this();
setParent(parent);
}
//具体需要执行的方法
public AbstractApplicationContext() {
this.resourcePatternResolver = getResourcePatternResolver();
}
//获取一个Source的加载器用于读入Spring Bean 定义资源文件
protected ResourcePatternResolver getResourcePatternResolver() {
return new PathMatchingResourcePatternResolver(this);
}
//设置双亲ioc容器
public void setParent(ApplicationContext parent) {
this.parent = parent;
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
getEnvironment().merge((ConfigurableEnvironment) parentEnvironment);
}
}
}

调用父类的构造方法执行完成后,返回FileSystemXmlApplicationContext类,执行setConfigLocations(configLocations)方法,该方法的定义在类AbstractRefreshableConfigApplicationContext中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//处理资源定义的数组,解析Bean文件的定义路径
public void setConfigLocations(String[] locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
//解析路径
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}

在资源定位的时候,支持下面两种方式:

  • ClasspathResource res = new ClasspathResource(“a.xml,b.xml”);
  • ClasspathResource res = new ClasspathResource(“new String(){‘a.xml’ , ‘b.xml’}”)
    具体实现的方式不在展开,感兴趣的可以去看一下源码实现

我们来看以上,程序执行到此处后,都做了哪些操作:

  1. 在AbstractApplicationContext中初始化了resourcePatternResolver(多资源文件的载入),用于获取Resource,关于何时使用后面再解释
  2. 将资源的定义路径保存在了configLocations数组中

到此,IOC容器根据资源定义路径获取Resouce的准备工作便完成了。

IOC容器的初始化过程

在开始分析初始化过程之前,先从宏观上对初始化的过程做一个简单的介绍,有一个大体框架的初始化模型,方便后面的理解,初始化过程分成了三个过程:

  • Resource定位
  • BeanDefinition的载入
  • 向IOC容器注册这些BeanDefinition信息。这个过程是通过BeanDefinitionRegistry接口的实现来完成的。最终注入到HashMap中去,这个hashmap就是持有beandefinition数据的。

下面来看一下FileSystemXmlApplicationContext中的关于refresh()方法的调用,实际调用的是AbstractApplicationContext中的refresh()方法,该方法定义如下:

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
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
//环境准备,获取容器启动的时间,设置活动标志,以及属性的初始化
prepareRefresh();
//在子类中启动resreshBeanfactory()方法
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//为BeanFactory配置容器属性
prepareBeanFactory(beanFactory);
try {
//设置BeanFactory的后置处理
postProcessBeanFactory(beanFactory);
//调用后置处理,为这些后置处理器在Bean的定义中向容器注册
invokeBeanFactoryPostProcessors(beanFactory);
//注册Bean的后续处理,在Bean创建过程中调用
registerBeanPostProcessors(beanFactory);
//初始化上下文消息机制
initMessageSource();
//初始化上下文中事件机制
initApplicationEventMulticaster();
//初始化其他特殊的Bean
onRefresh();
//检查监听Bean并且将这些Bean向容器注册
registerListeners();
//初始化所有的singleton beans , 设置lazy-init = true 的bean除外
finishBeanFactoryInitialization(beanFactory);
//发布容器事件,结束Refresh过程
finishRefresh();
}catch (BeansException ex) {
// 为防止Bean资源占用,在异常处理中,销毁已经生成的单件Bean
destroyBeans();
//重置Rest标志
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}

refresh()方法主要为IOC容器Bean的生命周期提供管理条件。Spring IOC容器的生成是从refreshBeanFactory()方法开始的,也就是执行了下面的代码:

1
2
3
4
5
6
7
8
9
10
11
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//使用委派模式,父类只是定义了方法,具体实现交给子类
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

在AbstractApplicationContext抽象类中,只是进行了refreshBeanFactory()方法的定义,方法的实现是在其子类AbstractRefreshableApplicationContext中实现的,在子类的定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) { //如果已经有容器,则销毁并关闭容器
destroyBeans();
closeBeanFactory();
}
try {
//创建IOC容器
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
//对容器进行定制化,如设置启动参数,开启注解自动装配等
customizeBeanFactory(beanFactory);
//委派模式,资源的加载交给子类实现,启动对BeanDefinition的载入操作
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

上面代码loadBeanDefinitions(beanFactory);我们说是一个委派模式,只是进行了方法的定义,具体实现则是由AbstractXmlApplicationContext类实现,在该方法中创建了读取器XmlBeanDefinitionReader的实例,然后把这个读取器在IOC容器中设置好,最后是启动读取器来完成对BeanDefinition在IOC容器中的载入,定义如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
//创建XmlBeanDefinitionReader
//即创建Bean读取器,并通过回调设置到容器中去,容器使用该读取器,读取Bean定义资源
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
//为Bean读取器设置资源加载器
beanDefinitionReader.setResourceLoader(this);
//设置一个Sax实体用于解析
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//当Bean读取器读取Bean定义的xml资源文件时,启用xml校验机制
initBeanDefinitionReader(beanDefinitionReader);
//Bean 读取器真正的实现加载的方法
loadBeanDefinitions(beanDefinitionReader);
}

XmlBeanDefinitionReader的初始化过程中,还进行了一些其他的操作,具体如下:

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
//调用父类的构造方法
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
super(registry);
}
//父类构造方法
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
//赋值
this.registry = registry;
//判断register是否是ResourceLoader 类型
if (this.registry instanceof ResourceLoader) {
this.resourceLoader = (ResourceLoader) this.registry;
}
else {
//为resourceLoader 新建一个资源加载器
this.resourceLoader = new PathMatchingResourcePatternResolver();
}
//判断register 是否是 EnvironmentCapable类型
if (this.registry instanceof EnvironmentCapable) {
this.environment = ((EnvironmentCapable) this.registry).getEnvironment();
}
else {
//初始化一个environment
this.environment = new StandardEnvironment();
}
}

通过上面代码发现,在创建XmlBeanDefinitionReader的过程中,完成了resourceLoader和eviironment的赋值操作。

首先得到BeanDefinition信息的Resource定位,然后直接调用XmlBeanDefinitionReader来读取,具体的载入过程是委托给BeanDefinitionReader来完成的。因为使用的FileSystemXmlApplicationContext, getConfigResources()方法返回的是null,所以程序会走第二个分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 //Xml Bean读取器加载Bean定义资源
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
//获取资源定位
Resource[] configResources = getConfigResources();
if (configResources != null) {
//Xml Bean读取器调用其父类AbstractBeanDefinitionReader读取定位
reader.loadBeanDefinitions(configResources);
}
//如果子类获取的Bean定义为空,则获取FileSystemXmlApplication构造方法中setConfigLocations方法设置的资源。
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinition(configLocations);
}
}

程序分析到这,来梳理一下上面的执行流程。

  • 在FileSystemXmlApplicationContext一共做了三件事
    • 调用了父类的构造器,进行了初始化
    • 设置了BeanDefinition的定义路径
    • 执行了Refresh()方法
  • refresh()方法来启动整个BeanDefinition的载入过程
    • 创建容器 DefaultListableBeanFactory
    • 创建了XmlXmlBeanDefinitionReader
    • 开始准备通过reader来加载资源

AbstractBeanDefinitionReader读取Bean定义资源,AbstractBeanDefinitionReader的loadBeanDefinitions方法源码如下:

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
//方法重载
public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
Assert.notNull(locations, "Location array must not be null");
int counter = 0;
String[] var3 = locations;
int var4 = locations.length;
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
counter += this.loadBeanDefinitions(location);
}
return counter;
}
public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
return this.loadBeanDefinitions(location, (Set)null);
}
//重载的最终执行方法
public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
//获取资源加载器
//上面提到过,XmlBeanDefinitionReader初始化时,在其父类中执行了加载器的初始化操作
//resourceLoader的类型为PathMatchingResourcePatternResolver
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
}
//判断类型
if (resourceLoader instanceof ResourcePatternResolver) {
try {
//将指定位置的Bean定义资源文件解析转化为Resource
//加载多个指定位置的资源定义文件
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
//读取Resource
int loadCount = loadBeanDefinitions(resources);
if (actualResources != null) {
for (Resource resource : resources) {
actualResources.add(resource);
}
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int loadCount = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isDebugEnabled()) {
logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
}
}

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
Assert.notNull(resources, "Resource array must not be null");
int counter = 0;
Resource[] var3 = resources;
int var4 = resources.length;

for(int var5 = 0; var5 < var4; ++var5) {
Resource resource = var3[var5];
counter += this.loadBeanDefinitions((Resource)resource);
}

return counter;
}

上面的方法主要进行了两件事:

  • 调用资源加载器获取资源 resourceLoader.getResource(location)
  • 真正执行加载功能的是子类XmlBeanDefinitionReader的loadBeanDefinitions方法

loadBeanDefinitions()方法在AbstractBeanDefinitionReader中并没有具体的实现,它会转到XmlBeanDefinitionReader中的loadBeanDefinitions(Resource resource)中运行:

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
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
//对xml资源进行编码处理
return this.loadBeanDefinitions(new EncodedResource(resource));
}
//方法重载,转入此方法执行
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if(this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Object currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if(currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if(!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
//将资源文件转换为类型为InputStream的I/O流
InputStream ex = encodedResource.getResource().getInputStream();
try {
//从InputStream中得到xML的解析源
InputSource inputSource = new InputSource(ex);
//编码如果不为null, 则设置inputSource的编码
if(encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
//读取数据
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
ex.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if(((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {
try {
//转化为Document 对象
Document doc = doLoadDocument(inputSource, resource);
//启动对Bean定义解析的详细过程,会用到Spring Bean的配置规则
return registerBeanDefinitions(doc, resource);
}
//删除了部分catch语句
catch (....) {
throw ex;
}
}

将XML文件转换成Document对象,解析过程由documentLoader实现,getValidationModeForResource(resource)验证xml文件的模式 DTD还是XSD,此方法不在展开。

1
2
3
protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {
return this.documentLoader.loadDocument(inputSource,getEntityResolver(), this.errorHandler,getValidationModeForResource(resource),isNamespaceAware());
}

创建Document 的过程:

1
2
3
4
5
6
7
8
9
10
11
public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
//创建文件解析工厂
DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
if (logger.isDebugEnabled()) {
logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
}
//创建文档解析器
DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
//解析Spring bean定义资源 ,并返回Document对象
return builder.parse(inputSource);
}

spring并没有对XML进行特殊的处理,使用了SAX对xml文档进行解析,操作分为三步:

  • 创建DocumentBuilderFactory
  • 创建DocumentBuilder
  • 解析inputSource对象,返回Document 对象

Document对象代表了一个XML文档的模型树,所有的其他Node都以一定的顺序包含在Document对象之内,排列成一个树状结构,以后对XML文档的所有操作都与解析器无关,直接在这个对象上操作即可。NodeList代表了包含一个或者多个Node的列表,操作上可以看作数组,使用getLength()获得列表中的节点数,item(int index ) 返回集合中第index个项。Node对象很少使用,会使用它的自对象Element,Attr 等。

至此,Spring IOC容器根据定位的Bean定义资源文件,并将其加载读入转换为document对象的过程完成。

上面略微呢有一点跑题,document对象的创建过程可能不是我们最关心的,我们关心就是Spring的BeanDefinition是怎样按照Spring的Bean语义要求进行解析并转化为容器内部数据结构的。 这个过程是在下面的方法中执行的,我们来看一下,具体的操作过程:

1
2
3
4
5
6
7
8
9
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
//创建DocumentReader来对XML格式的BeanDefinition进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
//获得容器中已经存在的Bean数量
int countBefore = getRegistry().getBeanDefinitionCount();
//具体的解析过程在这个方法中执行
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}

Bean定义资源的解析分为以下两个过程:

  • 通过调用xml解析器,将资源定义文件转换为Document对象,document对应并没有按照spring bean的规则进行解析。
  • 在完成通用xml解析之后,按照Spring的Bean规则对Document对象进行解析,这个过程是在documentReader中实现的。具体的操作是由DefaultBeanDefinitionDocumentReader完成的。
    处理的结果由BeanDefinitionHolder对象持有。解析过程由BeanDefinitionParserDelegate来实现。

来看下面的流程:

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
//根据Spring DTD 对bean定义的规则解析Bean定义Document对象
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
//获取xml描述符
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
//获得Document的根对象
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
//BeanDefinitionParserDelegate中定义了Spring Bean定义的XML文件的各种元素
//默认BeanDefinitionParserDelegate会处理”http://www.springframework.org/schema/beans“命名空间下元素及其属性
this.delegate = createDelegate(getReaderContext(), root, parent);

if (this.delegate.isDefaultNamespace(root)) {
//对于默认的命名空间,首先开始的是对profile属性解析
//profile用得最多的是DataSource在不同环境下使用不同的bean
//spring使用StringTokenizer来进行字符串的分割,但是jdk为了兼容性是推荐使用String.split()方法的:
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);
//从Document的根元素开始进行Bean定义的document对象
parseBeanDefinitions(root, this.delegate);
//在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性。空实现
postProcessXml(root);
this.delegate = parent;
}
protected BeanDefinitionParserDelegate createDelegate(XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {
BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);
delegate.initDefaults(root, parentDelegate);
return delegate;
}

解析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
protected void parseBeanDefinitions(Element root,BeanDefinitionParserDelegate delegate) {
//Bean定义的Document对象使用了Spring默认的XML命名空间
if (delegate.isDefaultNamespace(root)) {
//获取Document对象的所有子节点,NodeList的含义上面进行了介绍
NodeList nl = root.getChildNodes();
for (int i = 0; i < nl.getLength(); i++) {
Node node = nl.item(i); //获取Node节点
//判断Node是否是Element类型
if (node instanceof Element) {
Element ele = (Element) node;
//判断该元素是否属于Spring定义Bean的默认命名空间
if (delegate.isDefaultNamespace(ele)) {
//使用Spring的Bean规则解析元素节点
parseDefaultElement(ele, delegate);
}
else {
//使用用户自定义的规则进行解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
//没有使用spring默认的命名空间,则使用用户自定义的解析规则解析
delegate.parseCustomElement(root);
}
}

使用spring的Bean规则解析Document元素节点,有些元素节点是 等,则分别进行解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
//如果元素节点是<Import>导入元素,进行导入解析
if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
importBeanDefinitionResource(ele);
}
//如果元素节点是<Alias>别名元素,进行别名解析
else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
processAliasRegistration(ele);
}
//如果是<bean>转入此流程处理
else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
processBeanDefinition(ele, delegate);
}
//如果是<beans>转入此流程处理
else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
// recurse
doRegisterBeanDefinitions(ele);
}
}

主要看一下对bean标签的解析过程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void processBeanDefinition(Element ele,BeanDefinitionParserDelegate delegate) {
//BeanDefinitionHolder是对BeanDefinition的封装,delegate解析完成后使用holder封装,bdHolder 包含了id ,别名和BeanDefinition的信息
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
//向容器注册封装后的实例
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
....
}
//在Beandefinition向IoC容器注册完成以后,发送消息
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
}

下面看一下parseBeanDefinitionElement()方法的具体实现,对于BeanDefinition的注册时存放在ConcurrentHashMap中的,beanName变为存放的健:

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
public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
//获取id的值
String id = ele.getAttribute(ID_ATTRIBUTE);
//获取name的值
String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);
//分割name属性
List<String> aliases = new ArrayList<String>();
if (StringUtils.hasLength(nameAttr)) {
String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
aliases.addAll(Arrays.asList(nameArr));
}
//将id赋值给beanName
String beanName = id;
if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
beanName = aliases.remove(0);
if (logger.isDebugEnabled()) {
logger.debug("....");
}
}

if (containingBean == null) {
checkNameUniqueness(beanName, aliases, ele);
}
//该方法引发对Bean元素的详细解析
AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
//程序执行到此处,整个<bean>标签的解析就算结束了。一个beanDefinition就创建好了
if (beanDefinition != null) {
if (!StringUtils.hasText(beanName)) {
try {
if (containingBean != null) {
//如果不存在beanName,那么根据Spring中的提供的命名规则为当前bean生成对应的beanName
beanName = BeanDefinitionReaderUtils.generateBeanName(beanDefinition, this.readerContext.getRegistry(), true);
}
else {
beanName = this.readerContext.generateBeanName(beanDefinition);
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("....");
}
}
catch (Exception ex) {
error(ex.getMessage(), ele);
return null;
}
}
String[] aliasesArray = StringUtils.toStringArray(aliases);
//将信息封装到BeanDefinitionHolder中
return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
}
return null;
}

BeanDefinition可以看成是对定义的抽象,这个数据对象中封装的数据大多都是与定义相关的,也有很多就是我们在定义Bean时看到的那些Spring标记。这个BeanDefinition数据类型是非常重要的,它封装了很多基本数据,这些都是Ioc容器需要的,上面代码最后我们返回了一个BeanDefinitionHolder实例,这个实例封装了beanDefinition,beanName, aliase三个信息,beanDefinition中也包含了beanName,aliase信息。

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
public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {

this.parseState.push(new BeanEntry(beanName));
//这里只读取定义的<bean>中设置的class名字,然后载入到BeanDefinition中去,只是做个记录,并不涉及对象的实例化过程,对象的实例化过程实际是在依赖注入时完成的
String className = null;
if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
}

try {
//解析parent属性
String parent = null;
if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
parent = ele.getAttribute(PARENT_ATTRIBUTE);
}

//创建用于承载属性的AbstractBeanDefinition类型的GenereicBeanDefinition
//这里生成需要的BeanDefinition对象,为Bean定义的信息做载入做准备
AbstractBeanDefinition bd = createBeanDefinition(className, parent);
//这里对当前Bean元素进行属性解析,并设置description信息
parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
//解析元数据
parseMetaElements(ele, bd);
//解析lookup-method属性
parseLookupOverrideSubElements(ele, bd.getMethodOverrides());
//解析replaced-method属性
parseReplacedMethodSubElements(ele, bd.getMethodOverrides());
//解析构造函数参数
parseConstructorArgElements(ele, bd);
//解析property子元素
parsePropertyElements(ele, bd);
//解析qualifier子元素
parseQualifierElements(ele, bd);

bd.setResource(this.readerContext.getResource());
bd.setSource(extractSource(ele));
//返回BeanDefinition对象
return bd;
}
catch (ClassNotFoundException ex) {
...
}
catch (NoClassDefFoundError err) {
...
}
catch (Throwable ex) {
...
}
finally {
this.parseState.pop();
}
return null;
}

从上面的代码可以看出,要解析属性首先要创建用于承载属性的实例,也就是创建GenericBeanDefinition类型的实例,而代码createBeanDefinition(className,parent)的作用就是实现此功能。创建完承接的实例后,便可以进行各种属性的解析了,首先进行解析的是在标签中定义的各种属性,如scope, singleton,abstract,lazy-init等,然后再解析子标签中的属性,如:lookup-method ,constructor-arg等。解析完成之后关联到实例上,之所以能进行关联,是因为xml中所有的配置都能在GenericBeanDefinition的实力类中找到对应的配置。 此时容器还没有起作用,要想起作用,需要向容器进行注册。

分析到这,已经完成了xml文件向BeanDefinition的转化,每个一个标签都会转化成一个BeanDefinition对应的实体。实体中包含了中定义的所有属性。

BeanDefinition在IOC容器中的注册

前面只是进行了BeanDefinition在IOC容器中的载入和解析过程,这些动作完成后,已经完成了定义的数据转化为BeanDefinition的过程。下面代码继续执行,看一下注册的过程,也就是processBeanDefinition函数中的BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder,getReaderContext().getRegistry())的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//registerBeanDefinition()方法的具体实现
public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)throws BeanDefinitionStoreException {

//获取beanName
String beanName = definitionHolder.getBeanName();
//使用beanName作为唯一标识注册
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

//如果解析的BeanDefinition有别名,也要根据别名在注册一遍,不然根据别名找不到相应的信息
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
//beanName -> alias ,先将alias转换为beanName,在查找
registry.registerAlias(beanName, alias);
}
}
}

最终承接注册任务方法是在DefaultListableBeanFactory类中定义的,为了更好的排版,我对下面的代码进行了删减,主要删除了抛出异常信息和日志信息,并不影响代码的逻辑,对于beanDefinition的注册,做了一些验证之后,直接将beanDefinition放入了Map中:

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
 //向IoC容器注册解析的BeanDefiniton 
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {

if (beanDefinition instanceof AbstractBeanDefinition) {
try {
//注册前的最后一次校验
//主要是对AbstractBeanDefinition属性中的methodOverrides校验
((AbstractBeanDefinition) beanDefinition).validate();
}
catch (BeanDefinitionValidationException ex) {
....
}
}

BeanDefinition oldBeanDefinition;
//检查是否有同名的beanName存在,判断allowBeanDefinitionOveriding属性
oldBeanDefinition = this.beanDefinitionMap.get(beanName);
if (oldBeanDefinition != null) {
if (!isAllowBeanDefinitionOverriding()) {
throw ...
}
else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
// e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
if (this.logger.isWarnEnabled()) {
this.logger.warn("....");
}
}
else if (!beanDefinition.equals(oldBeanDefinition)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("....");
}
}
else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("...");
}
}
//如果允许覆盖则执行覆盖操作
this.beanDefinitionMap.put(beanName, beanDefinition);
}
else {

//判断是否已经有其他的Bean开始初始化
//在容器启动的最后会预初始化所有的singleton beans
if (hasBeanCreationStarted()) {
//注册的过程中需要线程同步,以保证数据的一致性
synchronized (this.beanDefinitionMap) {
//注册
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
if (this.manualSingletonNames.contains(beanName)) {
Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
updatedSingletons.remove(beanName);
this.manualSingletonNames = updatedSingletons;
}
}
}
else {
//正常情况下应该走此分支
//将BeanDefinition放入Map中,此map中保存了所有的BeanDefinition
this.beanDefinitionMap.put(beanName, beanDefinition);
//这个ArrayList中会按照bean配置的顺序保存每一个注册的Bean的名字
this.beanDefinitionNames.add(beanName);
//手动注册singleton bean
this.manualSingletonNames.remove(beanName);
}
this.frozenBeanDefinitionNames = null;
}

if (oldBeanDefinition != null || containsSingleton(beanName)) {
resetBeanDefinition(beanName);
}
}

至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现 在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

依赖注入

执行完上面的操作后,IOC容器已经实现了对Bean管理定义的相关数据,但是此时IOC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况下发生:

  • 用户第一次通过getBean()方法想容器索取时,进行依赖注入
  • 当用户在Bean的定义中为配置了lazy-init属性,让容器在解析注册时进行欲初始化,触发依赖注入

AbstactBeanFactory 通过getBean()函数获取被管理的Bean,但是因为lazyinit默认为false,所以spring会进行部分实例的初始化操作,让我们回退到AbstactApplicationContext类的finishBeanFactoryInitialization(beanFactory)方法,该方法进行了所有单例类的初始化操作,初始化的动作包装在了getBean()方法中,这个方法是获取Bean的地方,也是依赖注入发生的地方,对genBean的调用会转入到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
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
//根据执行的名称获取容器管理的Bean,已经初始化就直接返回,否则就先初始化在返回
protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException {
//提取定义的beanName,如果是别名,则将别名转换成规范的BeanName
final String beanName = transformedBeanName(name);
//定义Bean
Object bean;

//检查缓存中或者实例工厂中是否有对应的实例,单例模式的bean只创建一次
Object sharedInstance = getSingleton(beanName);
//如果实例已经创建,进入if分支 ,简单介绍一下参数args,一般情况下args为null,如果args不为null,则不是为了得到bean,而是为了创建bean
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("...");
}
else {
logger.debug("...");
}
}
//返回对应的实例,getObjectForBeanInstance完成的是FactoryBean的相关处理,已取得FactoryBean的生产结果,此处是FactoryBean和BeanFactory有区别。一个是创建工厂,一个是管理Bean工厂不一样。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
//只有在单例情况下才会尝试解决循环依赖的问题,所谓循环依赖,是指:A中有B,B中有A , 形成了互相的引用
if (isPrototypeCurrentlyInCreation(beanName)) {
// 缓存中有指定名字的Bean但是由于循环引用创建失败了
throw new BeanCurrentlyInCreationException(beanName);
}
//检查一下这个BeanDefinition在容器中是否存在
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
//如果当前容器不存在这个BeanDefinition,检查父容器中是否存在
String nameToLookup = originalBeanName(name);
if (args != null) {
//返回父容器的查询结果
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
//委派父级容器进行查找
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
//不仅仅是做类型检查, 这里要进行记录
if (!typeCheckOnly) {
//向容器标记指定的Bean已经被创建
markBeanAsCreated(beanName);
}
try {
//执行到这,需要创建新的Bean了。无论是单例还是原型。根据名字获取Beandefinition
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);

//先初始化所有的依赖bean
//注意这里的依赖是指定义在depends-on中的依赖
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
//检查一下循环依赖
if (isDependent(beanName, dep)) {
throw new BeanCreationException(。。。);
}

//注册依赖关系
registerDependentBean(dep, beanName);
//先初始化依赖项
getBean(dep);
}
}

//创建单例模式Bean实例
if (mbd.isSingleton()) {
//使用了匿名内部类,创建Bean实例对象,并且注册给所依赖的对象
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
//创建bean,如果有父级继承,则合并子类和父类的定义
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
//销毁单例beanName对象实例
destroySingleton(beanName);
throw ex;
}
}
});
//获取给定beanName的实例对象
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
//创建prototype的实例
else if (mbd.isPrototype()) {
//原型模式每次都会创建一个新的对象
Object prototypeInstance = null;
try {
//回调beforPrototypeCreateion方法,默认的功能是注册当前创建的原型对象
beforePrototypeCreation(beanName);
//创建实例
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
//回调afterPrototypeCreation方法,默认的功能告诉IOC容器指定bean的原型对象不在创建了
afterPrototypeCreation(beanName);
}
//获取给定的beanName实例对象
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
//如果不是单例或者原型的话,则委托给响应的实现类来处理,例如request ,session , application等生命周期
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("...");
}
try {
//使用匿名内部类获取一个指定生命周期范围的实例
Object scopedInstance = scope.get(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
}
});
//获取给定Bean的实力对象
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(...);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
//最后检查一下类型对不对,不对的话就抛出异常,对的话就返回
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug(....);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
//将bean返回,此时的bean已经包含了依赖关系
return (T) bean;
}

OK,上面的流程走完了,接下来该分析分支方法了, 没错,就是那个方法crateBean(),其定义如下:

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
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;

//确保BeanDefinition中的class被加载
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}

//准备方法覆写,涉及到一个概念:MethodOverrides,来自于Bean定义的<lookup-method>和<replaced-method>。感兴趣的自行研究
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}

try {
//让BeanPostProcessors 有机会返回一个代理实例而不是bean实例
//要彻底了解清楚这个,需要看InstantiationAwwareBeanPostProcessor接口
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
//核心方法,创建bean
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}

继续来看 doCreateBean()方法:

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
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)throws BeanCreationException {

//这个BeanWrapper是用来持有创建出来的Bean对象的
BeanWrapper instanceWrapper = null;

if (mbd.isSingleton()) {
//如果是singleton,先把缓存中的同名Bean清除
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
//创建Bean的地方,由crateBeanInstance完成
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
//这个就是Bean里面定义的类的实例
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null):
mbd.resolvedTargetType = beanType;

// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}

// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
//解决循环依赖问题
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}

// Initialize the bean instance.
Object exposedObject = bean;
try {
//负责装配属性,给属性赋值
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {

// 处理初始化后的各种回调
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}

if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(。。。);
}
}
}
}

// Register bean as disposable.
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(。。。);
}

return exposedObject;
}

到此,doCreateBean方法便执行完了,上面的方法主要执行了三个步骤:

  • 创建Bean实例createBeanInstance方法
  • 依赖注入populateBean方法
  • 回调方法initializeBean

下面介绍与依赖注入关系特别密切的方法createBeanInstance和populateBean方法。这个方法的主要作用就是实例化我们指定的类。

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
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {
//确保已经加载了此class
Class<?> beanClass = resolveBeanClass(mbd, beanName);
//校验这个类的访问权限
if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
throw new BeanCreationException(....);
}

if (mbd.getFactoryMethodName() != null) {
//采用工厂方法实例化
return instantiateUsingFactoryMethod(beanName, mbd, args);
}

//使用构造函数实例化
boolean resolved = false;
boolean autowireNecessary = false;
if (args == null) {
synchronized (mbd.constructorArgumentLock) {
if (mbd.resolvedConstructorOrFactoryMethod != null) {
resolved = true;
autowireNecessary = mbd.constructorArgumentsResolved;
}
}
}
if (resolved) {
if (autowireNecessary) {
//构造函数注入
return autowireConstructor(beanName, mbd, null, null);
}
else {
//无参构造函数
return instantiateBean(beanName, mbd);
}
}

//判断是否采用有参构造函数
Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
if (ctors != null ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
//构造函数依赖注入
return autowireConstructor(beanName, mbd, ctors, args);
}

//调用无参构造函数
return instantiateBean(beanName, mbd);
}

在创建实例时,重要的是下面代码:

1
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);

继续跟进一下:

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

判断一下是否存在方法覆写,如果不存在就使用java反射的方式创建实例,否则使用CGLIB来创建实例。

在这简单说一下,spring创建Bean的两种方式,一种是通过BeanUtis(JVM的反射功能,必须要基于接口才能实现),另一种就是CGLIB来生成。具体的不做深入分析,会放入AOP中来说明。到这实例的创建就完成了, 下面说一下属性的注入.

bean 属性注入,上面的代码已经完成了Bean对象的实例化,实例化对象已经生成,怎样把这些Bean对象的依赖关系处理好,依赖关系已经保存在了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
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
//获取property的值。来自于BeanDefinition中。
PropertyValues pvs = mbd.getPropertyValues();
//判断实例是否为空
if (bw == null) {
//实例为空,属性不为空,抛出异常
if (!pvs.isEmpty()) {
throw new BeanCreationException(。。。);
}
else {
return;
}
}

// 到这步的时候,bean 实例化完成(通过工厂方法或构造方法),但是还没开始属性设值,
// InstantiationAwareBeanPostProcessor 的实现类可以在这里对 bean 进行状态修改,
boolean continueWithPropertyPopulation = true;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 如果返回 false,代表不需要进行后续的属性设值,也不需要再经过其他的 BeanPostProcessor 的处理
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}

if (!continueWithPropertyPopulation) {
return;
}
//开始进行依赖注入过程,先处理autowire的注入
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

// 通过名字找到所有属性值,如果是 bean 依赖,先初始化依赖的 bean。记录依赖关系
if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}

// 通过类型装配。复杂一些
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;
// 这里有个非常有用的 BeanPostProcessor 进到这里: AutowiredAnnotationBeanPostProcessor
// 对采用 @Autowired、@Value 注解的依赖进行设值,这里的内容也是非常丰富的,不过本文不会展开说了,感兴趣的读者请自行研究
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
// 设置 bean 实例的属性值
applyPropertyValues(beanName, mbd, bw, pvs);
}

initializeBean属性注入完成后,这一步其实就是处理各种回调了。

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
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 {
// 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// BeanPostProcessor 的 postProcessBeforeInitialization 回调
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
// 处理 bean 中定义的 init-method,
// 或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法
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()) {
// BeanPostProcessor 的 postProcessAfterInitialization 回调
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}

转载自-简书