什么是循环依赖?就是两个Bean相互引用,比如用@Autowire 相互注入。
那么Spring是如何解决这个问题的呢?在Bean还未完全实例化前(类只实例化了一部分),将bean提前暴露出来,可以被其他Bean引用。
源码解析:
问题1:什么情况下需要提前暴露?
Spring托管的bean是通过getBean()-->doCreateBean()创建的。
正常情况下,单例模式,第一次调用getBean单例初始化完成后,直接放入cache了,后面再次调用直接从cache拿,不用走doCreateBean 了。
当有循环依赖时候,第二次调用getBean代码earlySingletonExposure就会=true,那么
就会触发行提前暴露bean的逻辑。
关键代码:addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
AbstractAutowireCapableBeanFactory.doCreateBean();
问题2: 提前暴露出去的对象是指定类型的Bean的实例本身吗?
不是的,是一个ObjectFactory用于创建该Bean实例 。因为Spring AOP机制,bean在后续实例化过程中可能会被BeanPostProcess处理,生成一个Proxy对象。
问题3: 是怎么提前暴露出去的?
其实很简单,遍历所有的BeanPostProcessor ,看是不是SmartInstantiationAwareBeanPostProcessor 对象(该接口是Spring AOP的顶级接口),不是(不需要AOP)直接返回原始bean。SmartInstantiationAwareBeanPostProcessor 提供了一个后门getEarlyBeanReference,该方法提前先调用了proxy bean的生成方法 wrapIfNecessary(),也就是说,AOP提前切入了。
问题4: 提前暴露出去的bean和最终生成的bean是同一个吗?
SmartInstantiationAwareBeanPostProcessor 接口做了强制规定,要么是同一个proxy对象,要么直接放回原始bean(不需要AOP的类)。
下面用AbstractAutoProxyCreator这个具体实现类的代码作进一步说明。 方法postProcessAfterInitialization() 加了一个判断,如果之前调用了getEarlyBeanReference(),完成了AOP,这里就不重复调用wrapIfNecessary()了(只是从earlyProxyReferences 做了remove),从而保证是同一个proxy对象。