[Исходный код фрейма] Процесс создания бина исходного кода анализа исходного кода Spring

вставьте сюда описание изображения

Вопрос: Как инициализируется singleton bean в Spring?

Все мы знаем, что Spring анализирует xml-файл, описанный как BeanDefinition, анализирует BeanDefinition и, наконец, создает Bean и помещает Bean в пул singleton, так что же делает Spring в процессе создания Bean.

Самый важный метод в основном методе Spring Refresh() — это метод finishBeanFactoryInitialization() , который отвечает за инициализацию всех одноэлементных компонентов.

Метод FinishBeanFactoryInitialization() расположен на шаге 11 функции refresh().

вставьте сюда описание изображения

К этому моменту все BeanFactories в контейнере Spring были созданы, то есть BeanFactoryPostProcessorбыли инициализированы bean-компоненты, реализующие интерфейс. Остальное — инициализация singleton beans. Большинство наших бизнес-бинов — синглетоны. finishBeanFactoryInitializationЭтот шаг — создание экземпляров синглетонов, а не установка лениво загруженных бинов.

Spring будет finishBeanFactoryInitializationинициализировать все в этом методе singleton bean.

Хорошо, давайте посмотрим на логику внутри метода FinishBeanFactoryInitialization. Суть этого метода заключается в завершении настройки BeanFactory . На этом этапе завершается создание экземпляра контекста, включая все созданные одноэлементные объекты Bean .

вставьте сюда описание изображения

Ядро заключается в методе preInstantiateSingletons() . Основная задача метода preInstantiateSingletons — инициализация. До инициализации это также ряд суждений, например, загружен ли он лениво, является ли он фабричным компонентом (специальным компонентом , ответственный за компонент, созданный фабрикой), и, наконец, вызовите метод getBean().
вставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображения

Интерфейс , упомянутый в комментарии, SmartInitializingSingletonпозволяет компоненту выполнять некоторые операции после инициализации.
вставьте сюда описание изображения
вставьте сюда описание изображения

Хорошо, тогда основным методом по-прежнему является getBean()метод, функция метода getBean() заключается в загрузке и создании экземпляра Bean. doGetBean() вызывается внутри метода, давайте заглянем непосредственно внутрь метода **doGetBean()**.
вставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображения

Кодов много, в основном мы рассматриваем метод createBean().
вставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображения

Продолжим заглядывать внутрь метода doCreateBean.
вставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображения

Существует много методов, но в основном нам нужно сосредоточиться на трех методах.

  • createBeanInstance: создание экземпляра, по сути, заключается в вызове конструктора объекта для создания экземпляра объекта
  • populateBean: заполните атрибуты, этот шаг в основном предназначен для заполнения свойств зависимостей нескольких bean-компонентов.
  • initializeBean: вызовите метод инициализации в spring xml.

Из шагов инициализации одноэлементного компонента, описанных выше, мы можем знать, что циклические зависимости в основном возникают на первом и втором шагах. То есть круговые зависимости конструктора и круговые зависимости поля.

Затем мы должны начать с процесса инициализации, чтобы решить циклическую ссылку.Для синглтона существует один и только один объект за весь жизненный цикл контейнера Spring, поэтому легко подумать, что этот объект должен храниться в кеше Чтобы решить проблему одноэлементной циклической зависимости, используйте трехуровневый кеш.

Что такое кеш третьего уровня Spring?

Трехуровневый кеш в контейнере IOC Spring представляет собой структуру карты.

  • Кэш 1-го уровня (зрелые бобы)
    • singletonObjectsПул singleton хранит полностью инициализированные bean-компоненты, а bean-компоненты, взятые из кеша, можно использовать напрямую
  • Кэш L2
    • earlySingletonObjectsКэш объекта singleton, выставленного заранее, хранит исходный объект bean (еще не заполненный свойствами), который используется для решения циклической зависимости.
  • Кэш L3
    • singletonFactoriesКэш фабрики одноэлементных объектов хранит объекты фабрики компонентов для разрешения циклических зависимостей.

вставьте сюда описание изображения

Хорошо, разобравшись с кешем третьего уровня, давайте посмотрим на метод getSingleton() . Этот метод в основном используется для получения экземпляра singleton Bean с указанным именем из пула singleton.Метод внутренне реализует механизм поиска в трехуровневом кэше и получает объект экземпляра singleton Bean с указанным именем через механизм трехуровневого поиска. В то же время метод Синхронизированные блоки кода используется для обеспечения безопасности потоков в многопоточной среде.

вставьте сюда описание изображения

Итак, у нас есть вопрос, почему Spring использует трехуровневый кеш для решения проблемы циклических зависимостей.

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

Если теперь у нас есть объект A и объект B , определенное поле или сеттер A зависит от экземпляра объекта B , и в то же время определенное поле или сеттер B зависит от экземпляра объекта A », этот круговой ситуация зависимости.

Первый завершает первый шаг инициализации и заранее предоставляет себя singletonFactories.В это время он выполняет второй шаг инициализации и обнаруживает, что он зависит от объекта B. В этот момент он пытается получить(B) и обнаруживает, что B еще не создан. , поэтому пройдите процесс создания, B обнаруживает, что он полагается на объект A во время первого шага инициализации, поэтому он пытается получить (A), пробует кеш первого уровня singletonObjects (конечно, не , так как A не был полностью инициализирован), и пытается использовать кеш второго уровня EarlySingletonObjects (Нет), попробуйте трехуровневый кеш singletonFactories, поскольку A заранее раскрывает себя через ObjectFactory, поэтому B может получить объект A через ObjectFactory.getObject (хотя A не был полностью инициализирован, это лучше, чем ничего), B принимает После достижения объекта A успешно завершены фазы инициализации 1, 2 и 3. После полной инициализации он поместит себя в первый- кеш уровня singletonObjects.

Вернувшись к A в это время, A может получить объект B и успешно завершить свои собственные фазы инициализации 2 и 3. Наконец, A также завершает инициализацию и входит в кеш первого уровня singletonObjects, и к счастью, потому что B получил объект ссылка на A, поэтому объект A, который теперь содержит B, завершил инициализацию.

вставьте сюда описание изображения

Когда вы знаете этот принцип, вы должны знать, почему Spring не может решить проблему « метод построения A зависит от объекта экземпляра B, а метод построения B зависит от объекта экземпляра A »! Поскольку предпосылкой добавления трехуровневого кэша singletonFactories является выполнение конструктора, циклическая зависимость конструктора не может быть разрешена.

В следующем примере вы продемонстрируете внедрение конструктора и внедрение набора.

Напишите класс А класс Б

public class A {
    
    
    private B b;
    public A() {
    
    }
    public B getB() {
    
    
        return b;
    }
    public void setB(B b) {
    
    
        this.b = b;
    }
    public void method(){
    
    
        System.out.println("A方法调用");
    }
}
public class B {
    
    
    private A a;
    public B(){
    
    }
    public A getA() {
    
    
        return a;
    }
    public void setA(A a) {
    
    
        this.a = a;
    }
    public void method(){
    
    
        System.out.println("B方法调用");
    }
}

написать xml

    <bean id="b" class="com.lixiang.demo.B">
        <property name="a" ref="a"></property>
    </bean>
    <bean id="a" class="com.lixiang.demo.A">
        <property name="b" ref="b"></property>
    </bean>

тест

вставьте сюда описание изображения

Изменить XML-конфигурацию

    <bean id="b" class="com.lixiang.demo.B">
        <!--将a改成用构造器注入-->
        <constructor-arg name="a" ref="a"></constructor-arg>
    </bean>
    <bean id="a" class="com.lixiang.demo.A">
        <property name="b" ref="b"></property>
    </bean>

корректировка кода

public class B {
    
    
    private A a;
    public B(A a){
    
    
        this.a = a;
    }
    public A getA() {
    
    
        return a;
    }
    public void setA(A a) {
    
    
        this.a = a;
    }
    public void method(){
    
    
        System.out.println("B方法调用");
    }
}

тест

вставьте сюда описание изображения

Можно обнаружить, что внедрение с помощью конструктора является ненормальным.

Spring вводит механизм «предварительного раскрытия bean-компонентов»: при создании объекта A он сначала создаст пустой объект A и добавит его в пул кеша.

То есть «предварительно выставить Bean», а затем продолжить создание объекта B и внедрить его в объект A. При создании объекта B, поскольку объект A уже находится в пуле буферов, объект A можно получить напрямую, а затем объект B вводится в объект A для завершения инициализации Bean.

вставьте сюда описание изображения

Хорошо, теперь весь процесс создания Бина завершен. Мы рассматриваем конкретную реализацию следующих трех методов.

Во-первых, это метод createBeanInstance().
вставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображения

Затем метод populateBean()
вставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображениявставьте сюда описание изображения

Наконец, метод initializeBean()
вставьте сюда описание изображениявставьте сюда описание изображения

Итак, с процессом создания Spring bean-компонентов разобрались.

Не забудьте поставить лайк + подписаться!

вставьте сюда описание изображения

Supongo que te gusta

Origin blog.csdn.net/weixin_47533244/article/details/131213407
Recomendado
Clasificación