Понимание жизненного цикла IoC, AOP и bean-компонентов из процесса загрузки Spring

Spring

Базовыми функциями Spring являются IoC и AOP, а нашими bean-компонентами управляет Spring. Так как же Spring IoC генерирует эти bean-компоненты и как улучшает прокси-сервер AOP для указанного bean-компонента? Ответ кроется в процессе запуска Spring.

1. Spring IoC

1.1 Взгляд на Spring IoC с высоты птичьего полета

Для удобства здесь используется версия аннотации для запуска контейнера Spring IoC. Как показано ниже.

quicker_318594ba-8017-4221-89af-6ac25ef672b2.png

Здесь мы сначала говорим о резюме, а затем объясняем исходный код, сначала уточняем контекст, а затем углубляемся в детали, чтобы не запутаться в деталях.

quicker_c37fdb93-6ae9-46f0-be83-820a17c6a783.png

Как показано на рисунке выше, процесс запуска Spring можно разделить на две части:

  • Шаг 1: Разобрать в BeanDefinition: разобрать информацию об определении компонента в класс BeanDefinition.Независимо от того, определена ли информация о компоненте в xml или аннотирована аннотацией @Bean, ее можно преобразовать в класс BeanDefinition с помощью различных BeanDefinitionReaders.
    • Существует два типа BeanDefinition, RootBeanDefintion и BeanDefinition. RootBeanDefinition находится на системном уровне и представляет собой 6 bean-компонентов, которые необходимо загрузить для запуска Spring. BeanDefinition — это Bean, который мы определяем.
  • Шаг 2: Ссылаясь на информацию о классе, определенную BeanDefintion, создайте экземпляры компонентов через BeanFactory и сохраните их в кэше.
    • BeanFactoryPostProcessor здесь является перехватчиком.После создания экземпляра BeanDefinition, BeanDefinition может быть изменен до того, как BeanFactory сгенерирует Bean.
    • BeanFactory использует отражение для создания экземпляров bean-компонентов в соответствии с определением BeanDefinition.Процесс создания и инициализации bean-компонентов включает жизненный цикл bean-компонентов.Типичной проблемой является круговая зависимость bean-компонентов. Затем, перед созданием экземпляра bean-компонента, он решает, нуждается ли bean-компонент в улучшении, и решает, какой прокси использовать для создания bean-компонента.

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

quicker_6161358d-a49c-4cfb-ac29-14d1f89ce689.png

1.2 Исходный код Spring IoC

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

Первым шагом является создание нового контейнера.

quicker_dfe02bf9-d87d-45bf-8108-1db3fa5e4a50.png

Нажмите и посмотрите, вы можете увидеть, что есть три основных метода, пожалуйста, запомните эти три метода, this(); register(componentClasses); Refresh();

quicker_767126df-de5f-4aae-8864-ed51e35fc2bb.png

1.2.1 метод this()

Нажмите, чтобы ввести это, и увидите, что шесть RootBeanDefinitions зарегистрированы на внутреннем уровне, то есть BeanDefinition системного уровня.

quicker_c42e9e89-e1a6-4185-a6b7-c204b39eb649.png

Зайдя снова, вы увидите, что зарегистрированное BeanDefinition фактически помещено в кэш BeanFactory.

quicker_5b940fba-094c-45d3-a684-b4d691be33ff.png

Возьмем в качестве примера класс ConfigurationClassPostProcessor, который на самом деле является перехватчиком BeanFactoryPostProcessor. Обратите внимание, что эта часть кода обратного вызова будет выполняться только в функции refresh(). Таким образом, упомянутый ниже BeanFactoryPostProcessor не будет выполняться, а будет выполняться в функции refresh().

quicker_a74733ee-11af-438c-8377-b91177835edc.png

ConfigurationClassPostProcessor перехватывает класс конфигурации и анализирует определение Bean внутри. Его метод перехвата проверяет, является ли класс классом конфигурации.

quicker_e0e266c6-2042-4d50-8f45-19ae1e9d0011.png

Затем проанализируйте класс конфигурации.

quicker_abe3cc16-aa13-4245-b08b-716a1ed2f7bd.png

Разбор @Import и @Bean

quicker_86e76306-b324-46bb-b32d-2748a564686c.png

1.2.2 Метод регистрации (классы компонентов)

Этот метод в основном предназначен для регистрации класса конфигурации, переданного новым AnnotationConfigApplicationContext(xxxConfiguration.class).

quicker_74d24a9e-03e2-4940-b106-d94c5ee4bdb8.png

1.3 Метод обновления()

Это самый важный метод загрузки Spring. Нажмите, чтобы посмотреть. Среди них invokeBeanFactoryPostProcessor, как следует из названия, предназначен для вызова постпроцессора BeanFactory. registerBeanPostProcessors(beanFactory) регистрирует постпроцессоры бина. Постпроцессоры бина широко используются в Spring. Они могут перехватывать процессоры в процессе создания бина. Подобно BeanFactoryPostProcessor, они также являются перехватчиками.

quicker_0eafea75-df6b-46c2-b3dc-8cb8a63518d7.png

Нажмите на этот метод, finishBeanFactoryInitialization(beanFactory). Он является важным методом инициализации бинов. Компоненты могут быть определены с помощью @Bean или инициализированы с помощью FactoryBean.

quicker_ad92e8be-1532-4e78-a362-a873e04ae2d8.png

Нажмите getBean(beanName), чтобы увидеть, как создается компонент.В то же время это также жизненный цикл компонента.

quicker_b43cf220-352b-4988-96e1-bd3208ee3daf.png

см. метод createBean(beanName, mbd, args)

quicker_36ae1662-7304-4c8b-ab0a-72489276ee37.png

Процесс создания bean-компонента можно разделить на два этапа: создание экземпляра и инициализация. Создание экземпляра относится к созданию экземпляра компонента, а инициализация относится к заполнению (назначению свойств) свойств экземпляра компонента. Метод resolveBeforeInstantiation() выполняется до создания экземпляра компонента. Предоставляет постпроцессору компонента возможность вернуть прокси, и когда вы вызываете проксируемый компонент, вы фактически выполняете расширенный объект прокси.

quicker_b3dbfba4-72c8-43a8-b572-6663e5a7f084.png

Нажмите на метод doCreateBean. Вот жизненный цикл бина, такой как картинка, выпущенная в начале.

quicker_6161358d-a49c-4cfb-ac29-14d1f89ce689.png

Жизненный цикл бина, вы можете видеть, что экземпляр создается на первом шаге

quicker_1c9d022c-e97d-4814-80ce-8c46368d868f.png

Нажмите на метод createBeanInstance, чтобы войти, и вы увидите, что объект bean наконец-то создан посредством отражения Java.

quicker_04d3e466-1b00-4ac9-8e28-81dcba0edde8.png

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

quicker_aca26d8a-b28c-4f6d-a92c-301857b4781f.png

жизненный цикл фасоли

quicker_5640c1c9-7c55-4093-9a30-343c7e998ad9.png

На этом объяснение процесса запуска функции контейнера IoC компонента заканчивается.

Spring AOP

С точки зрения расширения прокси-сервера Spring, прежде чем мы увидим созданный bean-компонент в разделе контейнера IoC выше, мы фактически сначала определяем, нуждается ли bean-компонент в улучшении.Метод resolveBeforeInstantiation(beanName, mdbToUse).Обратите внимание, что этот метод находится перед bean-компонентом. То есть сначала определите, нужно ли создавать прокси, если нет, то создайте bean-компонент, в противном случае создайте прокси-объект.

Уже поздно, продолжение следует. Я напишу содержание части АОП завтра.

Я обновлю его.

Итак, как Spring Aop создает прокси?Давайте рассмотрим метод resolveBeforeInstantiation(beanName, bdbToUse).

Видно, что он вызывает метод постпроцессора бина InstantiationAwareBeanPostProcessor, судя по названию класса, он перехватывает фазу создания экземпляра бина, а не фазу инициализации. Нажмите, чтобы посмотреть, вы можете обнаружить, что он генерирует объект bean, вызывая метод обратного вызова InstantiationAwareBeanPostProcessor.

UiomuT.png

Вызовите метод postProcessBeforeInstantiation для создания объекта.

Uios2t.png

На этом пока остановитесь. Давайте посмотрим, как мы обычно используем Spring Aop.

Мы напишем аннотированный класс аспекта @Aspect и используем аннотацию @EnableAspectJAutoProxy для включения проксирования.

Uixh8S.png

Щелкните, чтобы обнаружить, что он импортирует класс AspectJAutoProxyRegistrar в контейнер Spring.

UFP9Nn.png

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

UFPfCq.png

Этот метод внедряет определение компонента класса AnnotationAwareAspectJAutoProxyCreator в контейнер.

UFi7SP.png

Класс AnnotationAwareAspectJAutoProxyCreator представляет собой InstantiationAwareBeanPostProcessor.

На данный момент это согласуется с вышеизложенным.InstantiateAwareBeanPostProcessorвыполняется при создании экземпляра bean-компонента.Если есть возвращаемый объект, используется объект, в противном случае создается экземпляр. Таким образом, роль аннотации @EnableAspectJAutoProxy состоит в том, чтобы добавить в контейнер класс InstantiationAwareBeanPostProcessor, перехватить создание bean-компонентов и сгенерировать прокси-объекты.

quicker_183097d7-606d-4d14-a9d5-896a174ed0d0.png

Обработчик перехвата выглядит следующим образом: он создает прокси-объект и возвращает его.

quicker_6adc4364-70bd-4133-bcd9-133c1bf3bf95.png

Нажмите на метод createProxy(beanClass, beanName, SpecificInterceptor, targetSource) и проследите базовый код. Вы можете обнаружить, что существует два способа создания динамического прокси. Если класс является интерфейсом, используйте динамический прокси JDK, в противном случае используйте Cglib-прокси.

UFAprT.png

На этом часть Aop объяснения кода закончена.

Среди них проблема циклической зависимости IoC и дизайн цепочки перехватчиков Aop могут быть рекомендованы для просмотра исходного кода, если вам интересно.