bean的初始化
Spring提供了两个核心功能,IOC和AOP
什么是IOC
IOC为控制反转或依赖注入,实际就是将对象之间的依赖关系由程序代码控制转为由Spring通过配置文件或注解完成。
文档介绍:
在 Spring 中,构成应用程序主干并由 Spring IoC 容器 Management 的对象称为 bean。
Bean 是由 Spring IoC 容器实例化,组装和以其他方式 Management 的对象。否则,bean 仅仅是应用程序中许多对象之一。
Bean 及其之间的依赖关系反映在容器使用的配置元数据中。
org.springframework.context.ApplicationContext接口代表 Spring IoC 容器,并负责实例化,配置和组装 Bean。
容器通过读取配置元数据来获取有关要实例化,配置和组装哪些对象的指令。配置元数据以 XML,Java 注解或 Java 代码表示。
它使您能够表达组成应用程序的对象以及这些对象之间的丰富相互依赖关系。
思考
- IOC是个容器,要完成对象的依赖关系注入,那么容器中必定要存放对象实例,所以猜测肯定有个Map或者List之类的集合来存放实例对象。
- 为了方便实例对象存放到集合中并进行管理,那么应该会定义一个类来统一表示集合中的所有bean信息。
猜测
要初始化bean,需要的步骤
- 读取配置文件并解析配置信息
- 实例化bean对象
- 将实例添加到容器的集合中
- 反射注入bean之间的依赖关系
Spring IOC的使用代码
public class DemoTest {
public static void main(String[] args) {
// 初始化容器
ApplicationContext act = new ClassPathXmlApplicationContext("bubugao-pay-center/config/spring.xml");
// 容器中获取bean实例
MerchantPointService pointService = (MerchantPointService) act.getBean("merchantPointServiceImpl");
调用bean的方法
System.out.println(pointService.getById(16L));
}
}
读取配置文件并解析配置信息
源码跟踪:ApplicationContext act = new ClassPathXmlApplicationContext("bubugao-pay-center/config/spring.xml");
class:XmlBeanDefinitionReader
method:loadBeanDefinitions()
XmlBeanDefinitionReader会读取文件信息,然后解析文件内容,将配置文件转为BeanDefinition
...省略
// 配置文件转成流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 加载流信息,解析流并转成beanDefinition
return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
}
finally {
inputStream.close();
}
...省略
method:doLoadBeanDefinitions
将文件流转为document,然后解析document,注册BeanDefinition
...省略
Document doc = doLoadDocument(inputSource, resource);
return registerBeanDefinitions(doc, resource);
...省略
method:registerBeanDefinitions
文件被转成document后,使用BeanDefinitionDocumentReader解析docuemtn,由docuemnt取出BeanDefinition
// 创建文档解析器
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
// 返回当前注册器中的BeanDefinition数量
int countBefore = getRegistry().getBeanDefinitionCount();
// 解析document,注册BeanDefinition
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
class:DefaultBeanDefinitionDocumentReader
XmlBeanDefinitionReader会将文件解析为document,然后交由DefaultBeanDefinitionDocumentReader对document解析,注册BeanDefinition
method:registerBeanDefinitions
获取document的根节点,然后根据节点内容解析出BeanDefinition,并注册BeanDefinition
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
// 取根节点信息
Element root = doc.getDocumentElement();
// 解析根节点,注册BeanDefinition
doRegisterBeanDefinitions(root);
一路断点跟踪代码,最终定位DefaultBeanDefinitionDocumentReader#processBeanDefinition()
class:DefaultBeanDefinitionDocumentReader
DefaultBeanDefinitionDocumentReader在解析标签时,会委托给delegate处理
method:processBeanDefinition
利用delegate解析出BeanDefinition,delegate会去解析标签的每个属性
// 将配置文件节点信息解析为BeanDefinition
BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
if (bdHolder != null) {
bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
try {
// 注册BeanDefinition信息
BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
}
catch (BeanDefinitionStoreException ex) {
getReaderContext().error("Failed to register bean definition with name '" +
bdHolder.getBeanName() + "'", ele, ex);
}
// 发送事件通知
getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
}
跟踪BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
最终会进入DefaultListableBeanFactory,执行registerBeanDefinition()方法,此方法中有关键的三行代码
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
this.manualSingletonNames.remove(beanName);
至此,BeanDefinition就被注册到容器中,容器中使用beanDefinitionMap存储BeanDefinition信息,看看beanDefinitionMap的定义
/** Map of bean definition objects, keyed by bean name */
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(256);
所以容器使用Map存储BeanDefinition,BeanDefinition是容器中bean的抽象,包含class名、id、等信息,这里并不是bean的实例化对象。
总结:
所以读取配置文件并解析配置信息的过程大致是这样:
- XmlBeanDefinitionReader读取配置文件,将配置文件转成文件流,然后将文件流解析为document对象信息
- 文件被转换成docuemnt后,由DefaultBeanDefinitionDocumentReader解析document,而真正解析document的是BeanDefinitionParserDelegate
DefaultBeanDefinitionDocumentReader委托BeanDefinitionParserDelegate解析document,BeanDefinitionParserDelegate返回BeanDefinitionHolder给DefaultBeanDefinitionDocumentReader - BeanDefinitionHolder包含了BeanDefinition信息,然后由BeanDefinitionRegistry注册BeanDefinition到容器中
- 容器使用Map存储BeanDefinition信息
BeanDefinition实例化
BeanFactory默认是不会初始化bean的,只有首次使用时才会初始化bean
ApplicationContext默认会初始化所有singleton的bean信息,并且singleton没有设置懒加载
代码跟踪,定位到BeanUtils#instantiateClass()方法,Spring使用反射创建bean实例信息
class:DefaultListableBeanFactory
初始化的逻辑实际就是循环之前注册的所有BeanDefinition信息,然后通过调用getBean()方法进行初始化
Spring首先回去实例缓存中查询,如果实例不存在则创建实例并放入缓存
method:preInstantiateSingletons
遍历BeanDefinition信息,通过getBean()方法进行初始化
...省略
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
if (isFactoryBean(beanName)) {
final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return ((SmartFactoryBean<?>) factory).isEagerInit();
}
}, getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
getBean(beanName);
}
}
else {
getBean(beanName);
}
}
}
...省略
class:AbstractBeanFactory
从缓存中获取bean,如果bean为空,则创建bean
method:doGetBean
...省略
// 缓存中获取
Object sharedInstance = getSingleton(beanName);
...省略
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
// 创建bean
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
...省略
class:DefaultSingletonBeanRegistry
method:getSingleton
创建bean,并缓存到singletonObjects
...省略
// 创建bean实例
singletonObject = singletonFactory.getObject();
newSingleton = true;
...省略
// 回写缓存
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
...省略
class:AbstractAutowireCapableBeanFactory
初始化bean实例的地方,bean通过反射创建后会通过BeanWrapper包装bean实例,实例被创建后会回到上层继续bean的初始化,完成bean的相关依赖注入
method:instantiateBean
try {
Object beanInstance;
final BeanFactory parent = this;
if (System.getSecurityManager() != null) {
beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
return getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
}, getAccessControlContext());
}
else {
// 反射创建实例
beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
}
// 实例包装成BeanWrapper返回
BeanWrapper bw = new BeanWrapperImpl(beanInstance);
initBeanWrapper(bw);
return bw;
}
catch (Throwable ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
}
总结
初始化过程:
- AbstractApplicationContext的refresh()方法中,ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
完成了BeanDefinition的加载,BeanDefinition会被缓存到DefaultListableBeanFactory的beanDefinitionMap中,然后在refresh()中调用finishBeanFactoryInitialization(beanFactory);完成bean的实例化 - 在DefaultListableBeanFactory的preInstantiateSingletons中会循环所有BeanDefinition信息,然后通过getBean()方法初始化实例
- getBean()方法最终会调用到AbstractBeanFactory的doGetBean()方法,然后先从DefaultSingletonBeanRegistry的singletonObjects缓存中获取bean实例
- 如果singletonObjects缓存中不存在bean实例,则调用到AbstractAutowireCapableBeanFactory创建bean实例
将实例添加到容器的集合中
由于在getBean之前都会先从缓存中获取bean实例,所以createBean后,一定会将bean放入缓存
class:DefaultSingletonBeanRegistry
method:getSingleton
// 如果是创建的bean实例,则写入缓存
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
method:addSingleton
将bean实例信息写入singletonObjects缓存
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
总结
- DefaultSingletonBeanRegistry的getSingleton()方法中,bean被创建后会调用addSingleton()方法缓存在singletonObjects中
反射注入bean之间的依赖关系
上面会初始化BeanDefinition中所有singleton且没有设置懒加载的bean实例
如果BeanA服务依赖BeanB服务,则会先实例化BeannB服务再实例化BeanA服务
class:AbstractAutowireCapableBeanFactory
Spring通过反射创建实例bean,但是这个bean还是个半成品,因为bean中的依赖属性是还没有注入的,所以bean创建之后必然需要注入依赖属性
method: doCreateBean
...省略
if (instanceWrapper == null) {
// 创建bean实例
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
...省略
// 完成依赖注入入口
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
...省略
method:populateBean
...省略
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
method:applyPropertyValues
...省略
// 完成依赖bean的创建
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
...省略
// 通过反射注入依赖bean
bw.setPropertyValues(new MutablePropertyValues(deepCopy));
...省略
依赖bean初始化
class:BeanDefinitionValueResolver
初始化依赖bean
method:resolveValueIfNecessary
...省略
if (value instanceof RuntimeBeanReference) {
RuntimeBeanReference ref = (RuntimeBeanReference) value;
return resolveReference(argName, ref);
}
...省略
method:resolveReference
经过一层层的调用后,最后依赖服务通过getBean初始化,这里就形成了一个递归初始化的调用过程
...省略
resolvedName = String.valueOf(doEvaluate(ref.getBeanName()));
bean = this.beanFactory.getBean(resolvedName);
...省略
这里往后再跟读代码,会发现,有专门存放依赖bean的Map,dependentBeanMap:存放bean被哪个bean所依赖,dependenciesForBeanMap:存放bean依赖了哪些bean
注入依赖
class: AbstractPropertyAccessor
method: setPropertyValues
...省略
for (PropertyValue pv : propertyValues) {
...省略
// 注入依赖
setPropertyValue(pv);
...省略
}
...省略
一路跟读代码,最后注入依赖的地方为:
class: BeanWrapperImpl(PropertyHandler)
method: setValue
...省略
ReflectionUtils.makeAccessible(writeMethod);
writeMethod.invoke(getWrappedInstance(), value);
...省略
总结
- AbstractAutowireCapableBeanFactory的doCreateBean()方法会完成bean的创建以及相关依赖bean的初始化和注入工作。
- AbstractAutowireCapableBeanFactory注入依赖bean的相关操作交给了AbstractPropertyAccessor处理,AbstractPropertyAccessor在setPropertyValues中完成依赖注入操作
- AbstractPropertyAccessor也是将注入操作交给了PropertyHandler处理
- PropertyHandler最终通过反射注入依赖