概述
经过前面几篇对Spring IoC的介绍,源码虽然很多,不过大家应该对这个过程有个总体的印象了。知道关键的部分在哪里了,对于以后定位问题以及做扩展都是非常有帮助的。难点应该在于finishBeanFactoryInitialization方法,这里对于Bean的获取和创建,实例化初始化过程是比较复杂,这里总的来回顾一下前面的过程。
回顾

我们主要聚焦DefaultListableBeanFactory这个类,它是个Bean工厂的实现类。
查看类图,我们还需要关注其父类:
AbstractAutowireCapableBeanFactory,自动装配工厂;
AbstractBeanFactory,抽象工厂类;
DefaultSingletonBeanRegistry,Bean的注册器。
具体关注的类和方法如下图:

从finishBeanFactoryInitialization入口进入;
然后会调用DefaultSingletonBeanRegistry #preInstantiateSingletons 实例化单例bean;
执行 getBean 尝试从缓存获取bean实例 getSingleton(beanName);
getSingleton(beanName) 真正执行的是getSingleton(String beanName, boolean allowEarlyReference);
一级缓存singletonObjects中有值,则直接返回;
没有缓存,则尝试从父级parentBeanFactory获取bean,执行getBean,有则直接返回;
没有父级parentBeanFactory,则要进入创建bean的步骤了;
有依赖其他bean,则注册一下其依赖的bean,registerDependentBean;
然后按不同的策略执行创建bean:
getSingleton(String beanName, ObjectFactory<?> singletonFactory);
singletonFactory.getObject 会执行createBean操作,实际是doCreateBean在做事;
在doCreateBean执行过程中,创建了半成品的bean实例,然后会执行一个addSingletonFactory,这个主要是往三级缓存singletonFactories里加入传入的匿名函数singletonFactory,它的getObject会执行getEarlyBeanReference获取提早曝光的bean,这是用来解决循环依赖的关键点。
然后进入属性填充,执行populateBean方法;
属性填充中发现有需要依赖的bean(假设前面的那个bean叫X,这里的这个bean叫Y,如果X依赖Y,Y又依赖X,这就形成了循环依赖关系),它会去再走一遍getBean流程(去获取Y),当这次执行到属性填充,填充前边的bean(Xbean)的时候,getSingleton(String beanName)被调用了,它从一级(singletonObjects)二级(earlySingletonObjects)缓存里获取不到值,就会从三级缓存singletonFactories里获取到值,然后执行它的getObject,获取提早曝光的bean,加入到二级缓存earlySingletonObjects里,这样就会把现在的这个bean(Ybean)创建完成,并加入到一级缓存里,完成后,就会继续执行前边那个bean(Xbean)的实例化,此时Ybean已经是完成态的bean,填充了Xbean的属性后,Xbean也会创建完成,加入到一级缓存里。所以整个循环依赖就这样解决了。
属性填充完后,会进行bean初始化initializeBean。
这样就是一个bean的获取和创建过程。
嗯,看起来比较绕,此时得有个图!
准备两个类TestAaService 、 TestBbService
package com.zhlab.ssm.demo.web.service;
public class TestAaService {
private String name;
private TestBbService testBbService;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TestBbService getTestBbService() {
return testBbService;
}
public void setTestBbService(TestBbService testBbService) {
this.testBbService = testBbService;
}
}
package com.zhlab.ssm.demo.web.service;
public class TestBbService {
private String name;
private TestAaService testAaService;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public TestAaService getTestAaService() {
return testAaService;
}
public void setTestAaService(TestAaService testAaService) {
this.testAaService = testAaService;
}
}
然后加入配置
<bean id="testAaService" class="com.zhlab.ssm.demo.web.service.TestAaService">
<property name="testBbService" ref="testBbService"></property>
</bean>
<bean id="testBbService" class="com.zhlab.ssm.demo.web.service.TestBbService">
<property name="testAaService" ref="testAaService"></property>
</bean>

从getBean("A")出发,会发生getBean("B"),而getBean("B")时又会发生getBean("A")这就形成循环依赖
※Spring中解决循环依赖的scope必须是单例,多例则不行。
还是从demo入口进入
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("applicationContext.xml");
关注getBean执行过程

整个过程如图所示。
总结
整个过程看起来比较绕,但是抓住主要的几个主干方法以及三个缓存的转换,慢慢就可以理清思路了。
网友评论