Spring source code parsing - cycle dependent solutions

Watch meters pocket Java.md

I. Introduction

Undertake "Spring Source resolve - to create a bean" , "Spring parse the source code - Create the bean instance" , then we talk about today, circular dependencies solutions that create the bean ObjectFactory.

二、ObjectFactory

boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
        isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
    if (logger.isDebugEnabled()) {
        logger.debug("Eagerly caching bean '" + beanName +
                "' to allow for resolving potential circular references");
    }
    // 为避免后期循环依赖,可以在bean初始化完成前将创建实例的ObjectFactory加入工厂
    /**
     * getEarlyBeanReference(beanName, mbd, bean)方法:
     * 对bean再一次依赖引用,主要应用SmartInstantiationAwareBeanPostProcessor
     * 其中我们熟知的AOP就是在这里将advice动态织入bean中,若没有则直接返回bean,不做任何处理
     */
    addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}

This code is not very complicated, but not too many people understand the role of this code, and that code only from the function to understand it is difficult to understand the meaning, we need to think about Spring's dependency from a global point of view Solution.
earlySingletonExposure: understand that early exposure of a single case from the literal meaning, we will not define what its scientific name, we are interested in what conditions affect this value.

  • mbd.isSingleton (): there is not much can be explained, whether it is this RootBeanDefinition represent a single case.
  • this.allowCircularReferences: whether to allow cyclic dependencies, Sorry, did not find how to configure in the configuration file, but is provided disposed AbstractRefreshableApplicationContext function may be provided by hard-coded or may be a custom namespace configuration, wherein hard-coded code is as follows.
ClassPathXmlApplicationContext bf = ClassPathXmlApplicationContext("aspectTest.xml" ); bt.setAllowBeanDefinitionOverriding(false);
  • isSingletonCurrentlylncreation (beanName): The bean is in creation. In Spring, there will be a special attribute default load state DefaultSingletonBeanRegistry of singletonsCurrentlylnCreation to record the bean, the former will start creating beanName recorded in property, create beanName will be removed from the property after the end of the bean in the bean. Then we follow the code of the record along the way but this property did not have much impression, this is the state where the record it? Record positions of different scope are not the same, we singleton, for example, function recorded in the singleton property is public Object getSingleton in DefaultSingletonBeanRegistry of (String beanName, ObjectFactory singletonFactory) beforeSingletonCreation function (beanName) and afterSingletonCreation (beanName), the these two functions are this.singletonCurrentlylnCreation.add (beanName) and this.singletonCurrentlylnCreation.remove (beanName) for recording the state of removal.

After the above analysis to understand whether we are single variable earl earlySingletonExposure example, whether to allow a circular dependency, the general terms of whether the corresponding bean being created. When these three conditions are met addSingletonFactory will perform the operation, then what role is it to join SingletonFactory? And at what time to call it?

We simplest Case circular dependencies AB, Class A Class B containing attributes, while class B will contain the attribute classes A, then the initialization process beanA as shown below:
beanA.md

上图展示了创建 beanA 的流程,图中我们看到,在创建 A 的时候首先会记录类 A 所对应的 beanName,并将beanA的创建工厂加入缓存中,而在对 A的属性填充也就是调用populate方法的时候又会再一次的对 B 进行递归创建。同样的,因为在 B 中同样存在 A 属性,因此在实例化 B 的的 populate 方法中又会再次地初始化 A ,也就是图形的最后,调用 getBean(A)。关键是在这里,有心的同学可以去找找这个代码的实现方式,我们之前已经讲过,在这个函数中并不是直接去实例化 A ,而是先去检测缓存中是否有已经创建好的对应的 bean ,或者是否已经创建好的 ObjectFactory,而此时对于A的 ObjectFactory我们早已经创建,所以便不会再去向后执行,而是直接调用 ObjectFactory去创建 A 。这里最关键的是 ObjectFactory的实现。

/**
 * getEarlyBeanReference(beanName, mbd, bean)方法:
 * 对bean再一次依赖引用,主要应用SmartInstantiationAwareBeanPostProcessor
 * 其中我们熟知的AOP就是在这里将advice动态织入bean中,若没有则直接返回bean,不做任何处理
 */
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

其中getEarlyBeanReference的代码如下:

protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, Object bean) {
    Object exposedObject = bean;
    if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
        for (BeanPostProcessor bp : getBeanPostProcessors()) {
            if (bp instanceof SmartInstantiationAwareBeanPostProcessor) {
                SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
                exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);
            }
        }
    }
    return exposedObject;
}

在 getEarlyBeanReference 函数中并没有太多的逻辑处理,或者说除了后处理器的调用外没有别的处理工作,根据以上分析,基本可以理清 spring 处理循环依赖的解决办法,在 B 中创建依赖 A 时通过 ObjectFactory 提供的实例化方法来中断 A 中的属性填充,使 B 中持有的 A 仅仅是刚刚初始化并没有填充任何属性的 A ,而这正初始化 A 的步骤还是在最开始创建 A 的时候进行的,但是因为 A 与 B 中的 A 所表示的属性地址是一样的,所以在 A 中创建好的属性填充自然可以通过 B 中的 A 获取,这样就解决了循环依赖的问题。

三、小结

大体上的原理就是这样,有什么不明白的地方,大伙可继续阅读如下文章:

https://blog.csdn.net/m0_38043362/article/details/80284577

https://blog.csdn.net/hzcao/article/details/78479593

http://book.51cto.com/art/201311/419098.htm

Based on the number of links to the public pocket rice

https://mp.weixin.qq.com/s/P7f0HLnyjHqoN4-rUm0ytQ

Welcome concern meters pocket Java, in a note to share and exchange learning Java platform.

Rice pocket Java.md

Guess you like

Origin www.cnblogs.com/midoujava/p/11291487.html