以下内容基于 Spring6.0.4。
创新互联坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站建设、网站设计、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的登封网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
关于 Spring 循环依赖,松哥已经连着发了三篇文章了,本篇文章松哥从源码的角度来和小伙伴们捋一捋 Spring 循环依赖到底是如何解决了。
小伙伴们一定要先熟悉前面文章的内容,否则今天的源码可能会看起来有些吃力。
接下来我通过一个简单的循环依赖的案例,来和大家梳理一下完整的 Bean 循环依赖处理流程。
假设我有如下 Bean:
@Service
public class A {
@Autowired
B b;
}
@Service
public class B {
@Autowired
A a;
}
就这样一个简单的循环依赖,默认情况下,A 会被先加载,然后在 A 中做属性填充的时候,去创建了 B,创建 B 的时候又需要 A,就会从缓存中拿到 A,大致流程如此,接下来我们结合源码来验证一下这个流程。
首先我们来看获取 Bean 的时候,如何利用这三级缓存。
小伙伴们知道,获取 Bean 涉及到的就是 getBean 方法,像我们上面这个案例,由于都是单例的形式,所以 Bean 的初始化其实在容器创建的时候就完成了。
图片
在 preInstantiateSingletons 方法中,又调用到 AbstractBeanFactory#getBean 方法,进而调用到 AbstractBeanFactory#doGetBean 方法。
图片
Bean 的初始化就是从这里开始的,我们就从这里来开始看起吧。
AbstractBeanFactory#doGetBean(方法较长,节选部分关键内容):
protected T doGetBean(
String name, @Nullable Class requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object beanInstance;
// Eagerly check singleton cache for manually registered singletons.
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// Fail if we're already creating this bean instance:
// We're assumably within a circular reference.
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// Check if bean definition exists in this factory.
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory abf) {
return abf.doGetBean(nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else if (requiredType != null) {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
else {
return (T) parentBeanFactory.getBean(nameToLookup);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
.tag("beanName", name);
try {
if (requiredType != null) {
beanCreation.tag("beanType", requiredType::toString);
}
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
try {
getBean(dep);
}
catch (NoSuchBeanDefinitionException ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
}
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
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;
}
});
beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
}
}
return adaptBeanInstance(name, beanInstance, requiredType);
}
这个方法比较长,我来和大家说几个关键的点:
以上就是 doGetBean 方法中几个比较重要的点。
其中有两个方法我们需要展开讲一下,第一个方法就是去三级缓存中查询 Bean 的 getSingleton 方法(步骤一),第二个方法则是去获取到 Bean 实例的 getSingleton 方法(步骤六),这是两个重载方法。
接下来我们就来分析一下这两个方法。
DefaultSingletonBeanRegistry#getSingleton:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
当我们第一次创建 A 对象的时候,很显然三级缓存中都不可能有数据,所以这个方法最终返回 null。
接下来看 2.1 小节步骤六的获取 Bean 的方法。
DefaultSingletonBeanRegistry#getSingleton(方法较长,节选部分关键内容):
public Object getSingleton(String beanName, ObjectFactory> singletonFactory) {
synchronized (this.singletonObjects) {
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
beforeSingletonCreation(beanName);
boolean newSingleton = false;
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
if (newSingleton) {
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
我们来看下 addSingleton 方法:
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
小伙伴们看一下,一级缓存中存入 Bean,二级缓存和三级缓存移除该 Bean,同时在 registeredSingletons 集合中记录一下当前 Bean 已经创建。
所以现在的重点其实又回到了 createBean 方法了。
createBean 方法其实就到了 Bean 的创建流程了。bean 的创建流程在前面几篇 Spring 源码相关的文章中也都有所涉猎,所以今天我就光说一些跟本文主题相关的几个点。
createBean 方法最终会调用到 AbstractAutowireCapableBeanFactory#doCreateBean 方法,这个方法也是比较长的,而我是关心如下几个地方:
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
// Initialize the bean instance.
Object exposedObject = bean;
try {
populateBean(beanName, mbd, instanceWrapper);
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
return exposedObject;
}
这里我比较在意的有两个地方,一个是调用 addSingletonFactory 方法向三级缓存中添加回调函数,回调函数是 getEarlyBeanReference,如果有需要,将来会通过这个回调提前进行 AOP,即使没有 AOP,就是普通的循环依赖,三级缓存也是会被调用的,这个大家继续往后看就知道了,另外还有一个比较重要的地方,在本方法一开始的时候,就已经创建出来 A 对象了,这个时候的 A 对象是一个原始 Bean,即单纯的只是通过反射把对象创建出来了,Bean 还没有经历过完整的生命周期,这里 getEarlyBeanReference 方法的第三个参数就是该 Bean,这个也非常重要,牢记,后面会用到。
第二个地方就是 populateBean 方法,当执行到这个方法的时候,A 对象已经创建出来了,这个方法是给 A 对象填充属性用的,因为接下来要注入 B 对象,就在这个方法中完成的。
由于我们第 1 小节是通过 @Autowired 来注入 Bean 的,所以现在在 populateBean 方法也主要是处理 @Autowired 注入的情况,那么这个松哥之前写过文章,小伙伴们参考@Autowired 到底是怎么把变量注入进来的?,具体的注入细节我这里就不重复了,单说在注入的过程中,会经过一个 DefaultListableBeanFactory#doResolveDependency 方法,这个方法就是用来解析 B 对象的(至于如何到达 doResolveDependency 方法的,小伙伴们参考 @Autowired 到底是怎么把变量注入进来的?一文)。
doResolveDependency 方法也是比较长,我这里贴出来和本文相关的几个关键地方:
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
//...
Map matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
// In case of an optional Collection/Map, silently ignore a non-unique case:
// possibly it was meant to be an empty collection of multiple regular beans
// (before 4.3 in particular when we didn't even look for collection beans).
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
Map.Entry entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
//...
}
而 descriptor.resolveCandidate 方法又开启了新一轮的 Bean 初始化,只不过这次初始化的 B 对象,如下:
public Object resolveCandidate(String beanName, Class> requiredType, BeanFactory beanFactory)
throws BeansException {
return beanFactory.getBean(beanName);
}
后续流程其实就是上面的步骤,我就直接来跟大家说一说,就不贴代码了。
现在系统调用 beanFactory.getBean 方法去查找 B 对象,结果又是走一遍本文第二小节的所有流程,当 B 创建出来之后,也要去做属性填充,此时需要在 B 中注入 A,那么又来到本文的 2.4 小节,最终又是调用到 resolveCandidate 方法去获取 A 对象。
此时,在获取 A 对象的过程中,又会调用到 doGetBean 这个方法,在这个方法中调用 getSingleton 的时候(2.1 小节的第一步),这个时候的执行逻辑就跟前面不一样了,我们再来看下这个方法的源码:
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// Quick check for existing instance without full singleton lock
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
synchronized (this.singletonObjects) {
// Consistent creation of early reference within full singleton lock
singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null) {
ObjectFactory> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
}
}
return singletonObject;
}
现在还是尝试从三级缓存中获取 A,此时一二级缓存中还是没有 A,但是三级缓存中有一个回调函数,当执行 singletonFactory.getObject() 方法的时候,就会触发该回调函数,这个回调函数就是我们前面 2.4 小节提到的 getEarlyBeanReference 方法,我们现在来看下这个方法:
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
Object exposedObject = bean;
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
for (SmartInstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().smartInstantiationAware) {
exposedObject = bp.getEarlyBeanReference(exposedObject, beanName);
}
}
return exposedObject;
}
这个方法有一个参数 Bean,这个参数 Bean 会经过一些后置处理器处理之后返回,后置处理器主要是看一下这个 Bean 是否需要 AOP,如果需要就进行 AOP 处理,如果不需要,直接就把这个参数 Bean 返回就行了。至于这个参数是哪来的,我在 2.4 小节中已经加黑标记出来了,这个参数 Bean 其实就是原始的 A 对象!
好了,现在 B 对象就从缓存池中拿到了原始的 A 对象,B 对象属性注入完毕,对象创建成功,进而导致 A 对象也创建成功。
大功告成。
老实说,如果小伙伴们认认真真看过松哥最近发的 Spring 源码文章,今天的内容很好懂~至此,Spring 循环依赖,从思路到源码,都和大家分析完毕了~感兴趣的小伙伴可以 DEBUG 走一遍哦~
本文名称:透过源码,捋清楚循环依赖到底是如何解决的!
网页地址:http://www.shufengxianlan.com/qtweb/news35/496235.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联