(说出来,我就不信面试敢说你没看过源码)
基本的核心流程: getBean->doGetBean->getSingleton->createBean->doCreateBean->createBeanInstance->addSingletonFactory->populateBean->applyPropertyValues->resolveValueNecessary->resolveReference
具体的流程请看下面的流程讲解。
public class A {
@Autowired
private B b;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
}
----------------------------------------------------------------------------------------------------------------
public class B {
@Autowired
private A a;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
}
----------------------------------------------------------------------------------------------------------------
<?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="a" class="com.ytao.domain.A">
<property name="b" ref="b"></property>
</bean>
<bean id="b" class="com.ytao.domain.B">
<property name="a" ref="a"></property>
</bean>
</beans>
----------------------------------------------------------------------------------------------------------------
public static void main(String[] args) {
ApplicationContext config = new ClassPathXmlApplicationContext("spring.xml");
B b = (B) config.getBean("b");
System.out.println("b对象为"+b.getA());
A a = (A) config.getBean("a");
System.out.println("a对象为"+a.getB());
}
----------------------------------------------------------------------------------------------------------------
输出结果:
A对象为com.ytao.domain.A@1c9b0314
22:26:16.439 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Returning cached instance of singleton bean 'a'
B对象为com.ytao.domain.B@45385f75
在讲的Spring的时候,此时我们必会看一个方法那就是refresh。它里面包含了Bean初始化的操作。在类
AbstractApplicationContext中的finishBeanFactoryInitialization 包含了spring容器中bean的创建流程。
此时我们进入了finishBeanFactoryInitialization,经过前面代码一些我们不关注的代码,我们直接走到相关创建bean逻辑代码 beanFactory.preInstantiateSingletons();,从在这里看才开始正儿八经的实例化
进入到了preInstantiateSingletons,同理我们直接关注创建bean的代码逻辑来到了this.getBean(beanName) ->doGetBean 。 注意这里它先遍历的是对象A
然后debug进入getBean -> doGetBean,在这里我们看到了有根据className获取实例的代码Object sharedInstance = getSingleton(beanName);
根据getSingleton进入来到了他的具体实现方法。 singletonObjects 其实就是实例化完毕后的spring 容器。在这里我们知道其实a对象还没有实例完成,此时我们直接走到return 返回一个null
因为此时在容器里我们获取不到我们就需要去创建Bean对象。此时我们来到了createBean方法。注意他是一个lamba表达式
根据createBean我们来到了doCreatebean方法 在经过了 createBeanInstance(beanName, mbd, args) 处理后,此时bean实际上已经是一个对象对象,我们先给他堆内存开辟一个空间。至于指向暂定未定。
当创建完成后,此时按照流程就应该进入一个类似add的方法。此时我们来到addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean))方法,点击方法并且进入。
逻辑如下:这里注意,这里放入的value并不是一个对象。这里方法我们放入的是我们之前看的lmaba表达式,其实也就是提前暴光的单例对象的Cache。
判断三级缓存有没有值,如果没把值放入三级缓存中。然后把二级缓存给清除掉(这里其实二级缓存就没有值)
这里注意下,当我们放进入的时候,此时A对象的结构为为如下的结果
走完之后,我们该进行填充属性啦。
进入到这个方法,我们直接看核心逻辑代码,这里我们来到了applyPropertyValues方法
此时到了我们知道此时到了进行填充的步骤啦,此时debug可以看到填充的并不是一个对象,而是RuntimeBeanRefence类型的参数b
此时我们需要处理我们要填充的值(实际上没成功,因为有依赖循环,继续往下看)
然后我们填充的值属于RuntimeBeanRefence类型的,我们进入这个方法。
来到这个方法,我们第二次看到getBean这个方法。
特点: 第一轮getBean的循环主要是创建A对象的RuntimeBeanRefence,且A且加入了三级缓存singletonFactories,但是填充B的时候发现没有值。开始了第二轮循环
这里特别的我这里会特别指出。重复的地方我就不在说明啦。这里需要强调是第二轮的参数是B (因为A找B找不到,然后B当参数去当做参数,去调用getBean)
重复的流程大致简述为:到了 Object sharedInstance = getSingleton(beanName); 发现三级缓存还是没有,
然后继续到创建对象到createBean->doCreateBean,注意这里的传参是第一轮对象A的参数–>b , 此时到了doCreateBean是为把A对象依赖的对象b创建出来。
然后老样子我们把创建好的对象,进入addSingletonFactory方法。把参数b放入singletonFactories当中。与此同时到了参数b的时候,此时老样子他也要经过applyPropertyValues方法,又要填充A。 然后根据上面的流程,你会发现你又到getBean方法。 开始套娃啦!
特点: 依赖b的时候,发现b又需要a,此时创建A的依赖参数b的RuntimeBeanRefence的引用,此时A,B都有了RuntimeBeanRefence的引用,且他们都加入了三级缓存singletonFactories
之前讲过,第一轮A作为参数,依赖B的时候,找不到B,第二轮。B当参数的时候,找到不A
此时第三轮,就是A还是当作参数。
此时,还是进入根据上面的循环我们还是进入了到了getSingleton,但是从一级缓存获取为null,且对象属于正在创建的过程中(经过第一轮的循环,此时对象A已经在创建过程中),我们有史以来不同的地方来啦,我们第一次走进去了if。
此时我们分别把三级的缓存的值,放入到二级缓存。注意他放入的是ObjectFactory。也就是之前说的lamdba表达式
这里注意上面图片的singletonObject = singletonFactory.getObject(); 我们debug进入可以看到它的实现如下。此时它经过了这个方法,并没有走任何方法直接返回的。
根据上面的结果,我们可以知道。 此时经过上一轮的处理,此时对象B已经有了对象,在经过下次循环时会直接获取到对象b然后进行set 属性即可。此时对象就已经是成品的状态。
(虽然还没有加入一级缓存,但实际上如果只考虑Bean的调用的话,其实二级缓存就够啦,三级缓存是为了解决aop代理对象的问题,后续会更新)