Инвентаризация SpringIOC: Циклические зависимости

Java задняя часть
Инвентаризация SpringIOC: Циклические зависимости

Общая документация:Каталог статей
Github : github.com/black-ant

Введение

Это предварительная статья, заметки SpringIOC в основном разобраны, но я так и не понял, как вывести их в виде документа.

На мой взгляд, если я потрачу время на сортировку документа, независимо от того, насколько он длинный, даже если я что-то забуду, я должен иметь возможность быстро его прочитать, когда я прочитаю его позже, вся система IOC будет выводить таким образом.

Вся система IOC слишком велика, даже если разобрать все предыдущие заметки, этого все равно недостаточно. Но сначала выберите что-нибудь хорошее, чтобы сказать, и посмотрите, сможете ли вы сначала разобраться с этой частью.

2. Функциональное явление

Циклическая зависимость означает, что три объекта зависят друг от друга.Когда зависимый Бин получается через getBean, формируется циклическая зависимость.



// 这里先使用 Scope 尝试使用 prototype 模式 
@Component
@Scope(value = "prototype")
public class BeanCService{}

// 当 BeanA , BeanB , BeanC 相互依赖时 , 结果是这样的 :
 The dependencies of some of the beans in the application context form a cycle:
   beanStartService (field private com.gang.BeanAService com.gang.BeanStartService.beanAService)
┌─────┐
|  beanAService (field private com.gang.BeanBService com.gang.BeanAService.beanBService)
↑     ↓
|  beanBService (field private com.gang.BeanCService com.gang.BeanBService.beanCService)
↑     ↓
|  beanCService (field private com.gang.BeanAService com.gang.study.BeanCService.beanAService)
└─────┘

Удалить@Scope(value = "prototype")После все ок
Циклические зависимости обрабатываются в шаблоне singleton.

3. Отслеживание источника

Давайте проанализируем с точки зрения исходного кода, как синглтон SpringIOC управляет циклическими зависимостями.

3.1 Процесс загрузки одноэлементного компонента

начало всего

Отправная точка, конечноAbstractBeanFactoryВ начале этот шаг будет подробно объяснен, когда будет создан bean-компонент.

C- AbstractBeanFactory 
    M- doGetBean :
        - Object sharedInstance = getSingleton(beanName) : 从缓存中获取Bean
        

можно увидеть,При создании первого BeanA введите DefaultSingletonBeanRegistry

// 继续深入 DefaultSingletonBeanRegistry , 其中有以下的参数
C180- DefaultSingletonBeanRegistry
    F01- private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
        ?- 单例对象的缓存:bean到bean实例的名称
        
    F02- private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
        ?- 单例工厂的缓存:ObjectFactory的bean名
        
    F03- private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
        ?- 早期单例对象的缓存:bean到bean实例的名称
        
    F04- private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
        ?- 一组已注册的单例,按注册顺序包含bean名称
        
    F05- private final Set<String> singletonsCurrentlyInCreation =Collections.newSetFromMap(new ConcurrentHashMap<>(16));
        ?- 当前正在创建的bean的名称
        
    F06- private final Set<String> inCreationCheckExclusions =Collections.newSetFromMap(new ConcurrentHashMap<>(16));
        ?- 当前在创建检查中被排除的bean的名称
        
    F07- private Set<Exception> suppressedExceptions;
        ?- 异常列表
        
    F08- private boolean singletonsCurrentlyInDestruction = false;
        ?- 标志是否正在销毁单例
        
    F09- private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
        ?- 一次性bean实例:从bean名称到一次性实例
        
    F10- private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
        ?- 包含bean名称之间的映射:bean名称到bean所包含的一组bean名称
        
    F11- private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
        ?- 依赖bean名称之间的映射:bean名称到一组依赖bean名称
        
    F12- private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
        ?- 依赖bean名称之间的映射:bean名称到bean依赖项的一组bean名称

Как создать одноэлементный компонент

// 当我们创建一个单例Bean 时
C180- DefaultSingletonBeanRegistry      
    M180_01- getSingleton(String beanName, boolean allowEarlyReference)
        - 首先从 Map<String, Object> singletonObjects  中获取
        - 如果没有 , 且正在创建 (->M180_02) , 则继续从 earlySingletonObjects 中获取
        - 如果还是没有 , 且需要创建早期引用 , 则继续从 this.singletonFactories 中获取
        -如果 singletonFactories 获取到了  , 将当前 bean 放入 singletonObjects 且从 singletonFactories 移除
    M180_02- isSingletonCurrentlyInCreation
        ?- 判断当前 Bean 是否已经在注册
        - singletonsCurrentlyInCreation.contains(beanName)
    
    
// M180_01 代码 : 分别从三个 ConcurrentHashMap 中获取对应的 Bean
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}


С точки зрения всего процесса, наиболее важным является получение экземпляров Bean из трех локальных кэшей CurrentHashMap.

PS: Заранее можно сказать, что при создании первого Бин он всегда будет существовать в кеше, даже если он не был полностью загружен

BeanABeanBBeanCsingletonObjectsearlySingletonObjectssingletonFactoriesПолучить(B) Получить BeanBПолучить(C) Получить BeanCПолучить(A) Получить BeanAПолучить BeanA из singletonObjects в первый разПолучить не удалось, и был созданПолучить BeanA из кеша с помощью Get(A)Приобретение не удалось, и его необходимо создать заранее.Получить BeanA из кеша с помощью Get(A)BeanABeanBBeanCsingletonObjectsearlySingletonObjectssingletonFactories

Давайте внимательно посмотрим на эти кеши:

Продолжайте искать вниз, чтобы увидеть, когда были размещены два объекта выше.

// 着重复习一下上面几个对象
 
singletonsCurrentlyInCreation : 当前正在创建的 Bean 名称集合
singletonObjects : 单例对象的缓存
earlySingletonObjects : 早期单例对象的缓存
singletonFactories : 单例工厂的缓存

3.2 singletonsCurrentlyInCreation

Шаг 1: куда вставляется singletonsCurrentlyInCreation

C180- DefaultSingletonBeanRegistry      
    M180_03- beforeSingletonCreation
    	?- this.singletonsCurrentlyInCreation.add(beanName) : 添加当前 BeanName
    M180_04- afterSingletonCreation
    	?- this.singletonsCurrentlyInCreation.remove(beanName) : 移除当前 BeanName
    
// 这里大概就清楚了 插入的方式
// PS : 以下方法中都会调用 beforeSingletonCreation 方法  , 三个方法处理完成后 , 就会移除
C- AbstractAutowireCapableBeanFactory
    M- getSingletonFactoryBeanForTypeCheck 
C- DefaultSingletonBeanRegistry
    M- getSingleton :  单例Bean 创建的位置
C- FactoryBeanRegistrySupport
    M- getObjectFromFactoryBean   

3.3 Хранение singletonObjects

Где хранятся singletonObjects

M180_05- addSingleton
    - this.singletonObjects.put(beanName, singletonObject)
        ?- 也就是说每添加一个 单例 ,都会往其中添加一个对象
    M- getSingletonMutex : 这是唯一一个有可能放入数据的地方了
        - return this.singletonObjects;

// 打断点跟踪后发现以下类中进行了调用: 
C- FactoryBeanRegistrySupport
    M- getObjectFromFactoryBean : 只是作为一个锁对象
C- AbstractApplicationEventMulticaster
    M- setBeanFactory 
        - this.retrievalMutex = this.beanFactory.getSingletonMutex() : 将对象进行了引用
        ?- 其中也大部分作为锁对象 , 没有进行操作

PS: Использование этого объекта в качестве синхронизированного объекта мониторинга может эффективно обеспечить уникальность

Сначала я думал, что ConcurrentHashMap тоже должен уметь гарантировать уникальность параллелизма, а потом подумал, уникальность здесь должна быть уникальностью бизнес-процесса,Например, если я хочу удалить здесь, вы не можете добавить это туда, и вы можете продолжить, когда я закончу.

где singletonObjects удалены


C180- DefaultSingletonBeanRegistry  
    M180_07- clearSingletonCache
        - 这里不止一个集合 , 是把所有的集合都清空了
        ?- 看了一下 , 主要是再 destroySingletons 流程中调用
    M180_08- removeSingleton
        - 移除单个单例时 ,此时时 remove

PS: то есть, когда синглтон будет уничтожен, данные будут очищены или удалены

// M180_07 代码
protected void clearSingletonCache() {
    synchronized (this.singletonObjects) {
        this.singletonObjects.clear();
        this.singletonFactories.clear();
        this.earlySingletonObjects.clear();
        this.registeredSingletons.clear();
        this.singletonsCurrentlyInDestruction = false;
    }
}
addSingletonsingletonObjectsclearSingletonCacheremoveSingletonпомещать в параметры, когда addSingletonFactoryКоллекция singletonObjectsУдалено в методе clearSingletonCacheметод removeSingletonaddSingletonsingletonObjectsclearSingletonCacheremoveSingleton

3.4 earlySingletonObjects

где хранятся EarlySingletonObjects

C180- DefaultSingletonBeanRegistry  
    M180_01- getSingleton(String beanName, boolean allowEarlyReference)
    	?- 还是之前获取的位置 , 可以看到 , 这里有一个参数是 allowEarlyReference
    	- this.earlySingletonObjects.put(beanName, singletonObject)

PS: это происходит, когда загружается начальный класс BeanA, в это время никакие зависимости не вводятся, только первая сборка

EarlySingletonObjects — это промежуточный кеш, который будет очищен после добавления Single Bean.

где EarlySingletonObjects очищается

C180- DefaultSingletonBeanRegistry     
    M180_09- addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) : 清除单个
    M180_07- clearSingletonCache : 清空所有
    M180_05- addSingleton : 清除单个

getSingletonearlySingletonObjectsaddSingletonFactoryclearSingletonCacheaddSingletonпоместить в параметры, когда getSingletonКоллекция EarlySingletonObjectsУдалено из метода addSingletonFactoryочистить в методе clearSingletonCacheУдалено из метода addSingletongetSingletonearlySingletonObjectsaddSingletonFactoryclearSingletonCacheaddSingleton

3.5 singletonFactories

singletonFactory — это одноэлементные фабрики.

// 还是先看下
C180- DefaultSingletonBeanRegistry      
    M180_07- addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory)
    	IF- 如果 singletonObjects (F01)包含 当前 BeanName
            TRUE- singletonFactories (F02) 添加当前 Bean 和 singletonFactory
                ?- this.singletonFactories.put(beanName, singletonFactory);

// PS : 单例工厂是哪个环节被调用的
首先 , getSingle 中 , 实际上接的是一个 lambda 表达式
C180- DefaultSingletonBeanRegistry      
    M180_01- getSingleton(String beanName, boolean allowEarlyReference)    
        - ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
        - singletonObject = singletonFactory.getObject();

// 该对象是在 AbstractAutowireCapableBeanFactory # doCreateBean 中生成的
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));

// 其中传入了一个 getEarlyBeanReference 方法 , 该方法会在 getObject 回调
() -> getEarlyBeanReference(beanName, mbd, bean) --- singletonFactory.getObject() 
// 最终会通过 SmartInstantiationAwareBeanPostProcessor 来处理生成
SmartInstantiationAwareBeanPostProcessor ibp = (SmartInstantiationAwareBeanPostProcessor) bp;
exposedObject = ibp.getEarlyBeanReference(exposedObject, beanName);    

// 最终会生成一个空的对象 , 放进去

PS: объект будет получен getSingleton в последующем для продолжения обработки.

DefaultSingletonBeanRegistrysingletonFactoriesgetSingletonremoveSingletonclearSingletonCacheпомещать в параметры, когда addSingletonFactoryКоллекция singletonFactoryудален из метода singletonFactoryметод removeSingletonочистить в методе clearSingletonCacheDefaultSingletonBeanRegistrysingletonFactoriesgetSingletonremoveSingletonclearSingletonCache

image-20210421095922482.png

image-20210421100927098.png

3.6 Почему создание прототипа невозможно

Это включает в себя процесс загрузки прототипа:

Создание прототипа выполняется в AbstractBeanFactory.

C171- AbstractBeanFactory 
    M171_02- doGetBean( String name, Class<T> requiredType,Object[] args, boolean typeCheckOnly)
        - 如果是 Singleton , 则 getSingleton
            ?- 走了缓存集合
        - 如果是 Prototype , 则 createBean
            ?- 这里是没有缓存类来处理的
    
// M171_02 伪代码
if (mbd.isSingleton()) {
    //.....
} else if (mbd.isPrototype()) {
    Object prototypeInstance = null;
    try {
        beforePrototypeCreation(beanName);
        prototypeInstance = createBean(beanName, mbd, args);
    }finally {
        afterPrototypeCreation(beanName);
    }
    bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}


Завершить процесс

BeanCsingletonObjectsearlySingletonObjectssingletonFactoriesПолучить BeanA из singletonObjects в первый разПолучить не удалось, и был созданПолучить BeanA из кеша с помощью Get(A)Приобретение не удалось, и его необходимо создать заранее.Получить BeanA из кеша с помощью Get(A)BeanCsingletonObjectsearlySingletonObjectssingletonFactories

Дополнительная информация: Система SingletonBeanRegistry

SingletonBeanRegistry001.jpg

Суммировать

Процесс обработки циклических зависимостей на самом деле очень прост, а длина невелика, в основном это использование нескольких коллекций кеша.

Эта статья в основном предназначена для того, чтобы увидеть, может ли документ иметь возможность быстро соответствовать

использованная литература

cmsblogs.com/?cat=206

woo woo .cn blog on.com/ поцелуй себя/ страх/ 114…

приложение