前言
上一篇我们整理了IoC相关的几个类体系架构,本篇从一小段代码开始Debug,看Spring具体的实现。
源码分析
从容器获取一个单例的Bean:
public static void main(String[] args) {// 入口,加载xml配置,刷新容器,见#1ApplicationContext context = new ClassPathXmlApplicationContext("spring/spring-ioc.xml");// 单例下这个getBean()实际上是从缓存中获取的StudentB studentB1 = (StudentB) context.getBean("studentB");StudentB studentB2 = (StudentB) context.getBean("studentB");// 输出的结果是一样的System.out.println("studentB1: " + studentB1);System.out.println("studentB2: " + studentB2);}
调用方法:org.springframework.context.support.AbstractApplicationContext#refresh
// #1 完成IoC容器的创建及初始化public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 预刷新处理,刷新上下文,设置启动数据,初始化环境数据prepareRefresh();// 重点,刷新初始化容器,完成BeanDefinition注册,见#2ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// 对IoC容器进行一些预处理,设置一些公共属性prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// 对BeanDefinition进行处理invokeBeanFactoryPostProcessors(beanFactory);// 注册BeanPostProcessor后置处理器registerBeanPostProcessors(beanFactory);// 初始化消息源initMessageSource();// 初始化应用事件广播器initApplicationEventMulticaster();// 初始化一些特殊的beanonRefresh();// 检测监听器并注册registerListeners();// 重点, 实例化所有剩余的单例bean(非懒加载方式)// Bean的IoC、DI都是发生在此步骤finishBeanFactoryInitialization(beanFactory);// 完成刷新,发布对应的事件finishRefresh();}catch (BeansException ex) {// 省略代码...}finally {// 省略代码...}}}
注册BeanDefinition
调用方法:org.springframework.context.support.AbstractApplicationContext#obtainFreshBeanFactory
// #2 刷新容器protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {// 主要是通过该方法完成IoC容器的刷新,见#3refreshBeanFactory();ConfigurableListableBeanFactory beanFactory = getBeanFactory();// 省略代码...return beanFactory;}
调用方法:org.springframework.context.support.AbstractRefreshableApplicationContext#refreshBeanFactory
// #3 刷新IoC容器protected final void refreshBeanFactory() throws BeansException {// 如果已经有IoC容器,则销毁if (hasBeanFactory()) {destroyBeans();closeBeanFactory();}try {// 创建默认的IoC容器 DefaultListableBeanFactoryDefaultListableBeanFactory beanFactory = createBeanFactory();beanFactory.setSerializationId(getId());// 设置工厂的属性,是否允许BeanDefinition覆盖和是否允许循环依赖customizeBeanFactory(beanFactory);// 加载BeanDefinition,这个抽象方法,具体的实现让具体的子类完成,见#4loadBeanDefinitions(beanFactory);synchronized (this.beanFactoryMonitor) {this.beanFactory = beanFactory;}}catch (IOException ex) {// 省略代码...}}
调用方法:org.springframework.context.support.AbstractXmlApplicationContext#loadBeanDefinitions
// #4 读取xml类型的资源文件protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {// 获取资源路径Resource[] configResources = getConfigResources();if (configResources != null) {// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源reader.loadBeanDefinitions(configResources);}// 获取资源路径,我们这里是:spring/spring-ioc.xmlString[] configLocations = getConfigLocations();if (configLocations != null) {// XML Bean读取器调用其父类AbstractBeanDefinitionReader读取定位的资源// 见#5reader.loadBeanDefinitions(configLocations);}}
调用方法:org.springframework.beans.factory.xml.XmlBeanDefinitionReader#loadBeanDefinitions
// #5 经过一系列的调用,包装,在这里开始解析xml文件获得BeanDefinitionpublic int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {// 省略代码...try {// 将资源文件转为流InputStream inputStream = encodedResource.getResource().getInputStream();try {InputSource inputSource = new InputSource(inputStream);if (encodedResource.getEncoding() != null) {inputSource.setEncoding(encodedResource.getEncoding());}// do开头的方法是真正执行过程,开始解析,见#6return doLoadBeanDefinitions(inputSource, encodedResource.getResource());}// 省略代码...}// 省略代码...}
调用方法:org.springframework.beans.factory.xml.XmlBeanDefinitionReader#doLoadBeanDefinitions
// #6 开始解析加载protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)throws BeanDefinitionStoreException {try {// 通过DOM4J加载解析XML文件,最终形成Document对象Document doc = doLoadDocument(inputSource, resource);// 通过对Document对象的操作,完成BeanDefinition的加载和注册工作,见#7return registerBeanDefinitions(doc, resource);}// 省略代码...}
调用方法:org.springframework.beans.factory.xml.XmlBeanDefinitionReader#registerBeanDefinition
// #7 又经过一系列的处理,会在添加到一个map中public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {BeanDefinition oldBeanDefinition;oldBeanDefinition = this.beanDefinitionMap.get(beanName);if (oldBeanDefinition != null) {// 省略代码...// 如果是重复的BeanDefinition的一系列处理判断}else {// 不是第一个BeanDefinition的处理逻辑// 但是我们这里没有标记,所以还是会走下面逻辑if (hasBeanCreationStarted()) {// 省略代码...}// 如果是第一个BeanDefinition的处理逻辑else {// 会存进一个map中,beanName是key,beanDefinition是value// beanName:就是bean的名称,我们这里是studentB// beanDefinition:储存着一个bean的详细信息,如下图this.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}this.frozenBeanDefinitionNames = null;}// 省略代码...}

BeanDefinition中的bean信息数据结构
创建Bean
前面已经完成了Bean信息的加载,接下来看下Bean是如何创建的,这里有个经典的循环依赖问题,也通过源码看Spring是如何处理的。
还是调用这个方法:org.springframework.context.support.AbstractApplicationContext#refresh
// 完成IoC容器的创建及初始化public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// 省略代码...try {// 省略代码...// 重点, 实例化所有剩余的单例bean(非懒加载方式)// Bean的IoC、DI都是发生在此步骤finishBeanFactoryInitialization(beanFactory);}catch (BeansException ex) {// 省略代码...}finally {// 省略代码...}}}
调用方法:org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {// 获取bean名称final String beanName = transformedBeanName(name);Object bean;// 从缓存或单例工厂中获取单例bean,见##1Object sharedInstance = getSingleton(beanName);//如果获取到单例bean,则走下面代码if (sharedInstance != null && args == null) {// 如果取出来的Bean实例是FactoryBean的Bean实例// 则需要从FactoryBean实例中产生一个对象实例。// FactoryBean可以对某类复杂Bean生成对象,BeanFactory则是任意对象bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);}//如果没有获取到单例bean,则走下面代码else {// 如果是原型模式的Bean发生循环引用,不处理,直接抛出异常if (isPrototypeCurrentlyInCreation(beanName)) {throw new BeanCurrentlyInCreationException(beanName);}// 省略代码...try {// 获取要实例化的bean的BeanDefinition对象final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);// 省略代码...// 如果是单例的Beanif (mbd.isSingleton()) {sharedInstance = getSingleton(beanName, () -> {try {// 创建单例Bean的主要方法,见##2return createBean(beanName, mbd, args);}catch (BeansException ex) {// 省略代码...}});// 完成 FactoryBean 的相关处理,并用来获取 FactoryBean 的处理结果bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);}// 如果是原型的Beanelse if (mbd.isPrototype()) {// 省略代码...}// 处理request或session的Beanelse {// 省略代码...}}// 省略代码...}// 省略代码...return (T) bean;}
调用方法:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry#getSingleton
// ##1,一级没有去二级拿,二级没有去三级拿,三级拿完移除并添加到二级中protected Object getSingleton(String beanName, boolean allowEarlyReference) {// 从一级缓存中获取单例对象Object singletonObject = this.singletonObjects.get(beanName);// isSingletonCurrentlyInCreation() :// 判断当前单例bean是否正在创建中,也就是没有初始化完成// 比如A的构造器依赖了B对象所以得先去创建B对象,或者在A的populateBean过程中依赖了B对象,得先去创建B对象// 这时的A就是处于创建中的状态。if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {synchronized (this.singletonObjects) {// 从二级缓存中获取单例beansingletonObject = this.earlySingletonObjects.get(beanName);// allowEarlyReference():// 是否允许从singletonFactories中通过getObject拿到对象if (singletonObject == null && allowEarlyReference) {// 从三级缓存中获取单例beanObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);if (singletonFactory != null) {// 通过单例工厂获取单例beansingletonObject = singletonFactory.getObject();// 从三级缓存移动到了二级缓存this.earlySingletonObjects.put(beanName, singletonObject);this.singletonFactories.remove(beanName);}}}}return singletonObject;}
调用方法:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#doCreateBean
// ##2 完成Bean实例的创建(实例化、填充属性、初始化)protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)throws BeanCreationException {// 省略代码...// bean初始化第一步:默认调用无参构造实例化Bean// 构造参数依赖注入,就是发生在这一步if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}// 实例化后的Bean对象final Object bean = instanceWrapper.getWrappedInstance();Class<?> beanType = instanceWrapper.getWrappedClass();if (beanType != NullBean.class) {mbd.resolvedTargetType = beanType;}// 省略代码...// 如果是单例且允许循环依赖且该Bean还在创建中boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&isSingletonCurrentlyInCreation(beanName));// 如果需要提前暴露单例Bean,则将该Bean放入三级缓存中if (earlySingletonExposure) {// 将刚创建的bean放入三级缓存中singleFactories(key是beanName,value是FactoryBean)addSingletonFactory(beanName,() -> getEarlyBeanReference(beanName, mbd, bean));}// Initialize the bean instance.Object exposedObject = bean;try {// bean初始化第二步:填充属性(DI发生在此步骤)populateBean(beanName, mbd, instanceWrapper);// bean初始化第三步:调用初始化方法,完成bean的初始化操作exposedObject = initializeBean(beanName, exposedObject, mbd);}// 省略代码...return exposedObject;}
循环依赖
什么是循环依赖?
循环依赖就是循环引用,两个或多个bean相互之间的持有对方。例如A依赖B,而B又依赖A,最终形成闭环,并且只有单例Bean的循环依赖可以通过setter注入方式来解决,构造注入无法解决,其他类型的Bean更无法处理。
循环依赖处理
先看看一个Bean实例化的三个步骤:
- createBeanInstance 调用对象的构造方法实例化对象,是“残缺的”
- populateBean 对象属性填充
- initializeBean 对象初始化
循环依赖发生在第2步,因此我们也在第2步来处理,处理的策略是利用缓存。例如对象A依赖对象B,对象B又依赖对象A,那么当对象A实例化后进行属性填充,需要填充对象B,这时又去实例化B,填充B对象的属性发现要实例化A,但此时Spring会先去缓存中查找,而缓存又分为三级缓存。
一级缓存:singletonObject,缓存单例Bean
二级缓存:earlySingletonObjects,缓存实例化后的Bean,提前曝光
三级缓存:singletonFactories,缓存的是单例对象工厂,对Bean做beanPostProcessor后置处理,处理后在添加到二级缓存中并同时删除三级缓存中的数据,它才是真正处理循环依赖的。
在看完org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean就会明白为什么只能处理单例的setter循环依赖,因为Bean实例化第一步就是调用构造器来实例化对象,而field初始化是可以延迟的。
参考资料
请你相信我所说的都是错的

