Анализ процесса запуска контейнера Spring IOC
При использовании Spring XML и аннотации являются двумя наиболее часто используемыми методами настройки.Хотя это два совершенно разных метода настройки, для контейнера IOC разница между двумя методами заключается в основном вBeanDefinition
на анализ. Для процесса запуска основного контейнера он остается прежним.
AbstractApplicationContext
изrefresh
Метод реализует основную логику запуска IOC-контейнера, а ключевые шаги в процессе запуска также могут соответствовать независимым методам в исходном коде. Далее сAbstractApplicationContext
Класс реализацииClassPathXmlApplicationContext
Main и сравните его другой класс реализацииAnnotationConfigApplicationContext
, чтобы интерпретировать процесс запуска контейнера IOC.
AbstractApplicationContext.refresh
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
}
// ...
}
}
Связь между ApplicationContext и BeanFactory
ClassPathXmlApplicationContext
и AnnotationConfigApplicationContext
Дерево наследования показано ниже. Оба наследуют отAbstractApplicationContext
.
ApplicationContext
является перевозчиком контейнера IOC, иBeanFactory
Это инструмент для работы с этим контейнером, и они тесно связаны и взаимодействуют друг с другом.refresh
метод реализованApplicationContext
иBeanFactory
Основной процесс взаимного сотрудничества, разница в основном в подклассеAbstractRefreshableApplicationContext
иGenericApplicationContext
реализованы вBeanFactory
как дляDefaultListableBeanFactory
,DefaultListableBeanFactory
определяется следующим образом:
DefaultListableBeanFactory
:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable
видимыйDefaultListableBeanFactory
ДостигнутоConfigurableListableBeanFactory
, а значит, настраиваемый и проходимый, а почему это возможно, давайте продолжим искать ответ.
Приобретение BeanDefinition
DefaultListableBeanFactory
используйте структуру Map для хранения всехBeanDefinition
Информация:
DefaultListableBeanFactory
:
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
Разрешение в ClassPathXmlApplicationContext
использоватьBeanDefinitionDocumentReader
(смотрите такжеDefaultBeanDefinitionDocumentReader.processBeanDefinition
метод) для анализа bean-компонента в xml какBeanDefinition
, затем поBeanDefinitionRegistry
зарегистрироваться наBeanFactory
середина.
Вход:AbstractApplicationContext.refreshBeanFactory
(вызывается при обновлении)
Разрешение в AnnotationConfigApplicationContext
пройти черезBeanDefinitionScanner
Сканировать объявления bean-компонентов, разрешитьBeanDefinition
и поBeanDefinitionRegistry
зарегистрироваться наBeanFactory
середина.
Вход:AnnotationConfigApplicationContext
конструктор.
Почему запись ClassPathXmlApplicationContext в методе refreshBeanFactory?
AbstractApplicationContext.refreshBeanFactory
Определяется следующим образом:
AbstractApplicationContext
:
protected abstract void refreshBeanFactory() throws BeansException, IllegalStateException
Visible — это абстрактный метод, реализованный в подклассах. Только "Обновляемый"BeanFactory
В этом методе будут реализованы определенные операции, такие какAbstractRefreshableApplicationContext
:
AbstractRefreshableApplicationContext
:
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
видимыйAbstractRefreshableApplicationContext.``refreshBeanFactory
метод проверитBeanFactory
Он уже есть(hasBeanFactory
), уничтожьте все бины, которые уже существуют (destoryBeans
) и закрыть (closeBeanFactory
) BeanFactory
, а затем создайте (createBeanFactory
)новый.
и GenericApplicationContext.refreshBeanFactory
Он проверит, первый ли это вызов, если нет, то выкинет исключение и никакая другая логика выполняться не будет, т.е.GenericApplicationContext
Не "обновляемый".
Анализ основного процесса
refresh
метод вAbstractApplicationContext
определено вobtainFreshBeanFactory
метод называетсяgetBeanFactory
метод, который используется для полученияBeanFactory
, вотDefaultListableBeanFactory
, без особых указаний большая часть методов и переменных будет взята изAbstractApplicationContext
и DefaultListableBeanFactory
.
BeanPostProcessor
BeanPostProcessor
Интерфейс позволяет разработчику получить обратный вызов, когда контейнер IOC создает экземпляр bean-компонента (postProcessAfterInitialization
и postProcessBeforeInitialization
метод). Многие уведомления внутри фреймворка Spring (Aware
) реализуется через этот интерфейс, напримерApplicationContextAwareProcessor
, ServletContextAwareProcessor
, их реализация будет вpostProcessBeforeInitialization
Метод проверяется, и если конкретный интерфейс реализован, то он будет вызыватьсяAware
Метод обратного вызова для отправки уведомления:
ServletContextAwareProcessor
:
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (getServletContext() != null && bean instanceof ServletContextAware) {
((ServletContextAware) bean).setServletContext(getServletContext());
}
if (getServletConfig() != null && bean instanceof ServletConfigAware) {
((ServletConfigAware) bean).setServletConfig(getServletConfig());
}
return bean;
}
существует postProcessBeanFactory
метод, подклассы могут передаватьсяbeanFactory.addBeanPostProcessor
способ добавить свойBeanPostProcessor
прибытьbeanFactory
, в конечном итоге будет сохранено вBeanFactory
из beanPostProcessors
(фактическиCopyOnWriteArrayList
) середина.prepareBeanFactory
иregisterBeanPostProcessors
Метод заключается в том, что эти bean-компоненты создаются и добавляются централизованно.
BeanFactoryPostProcessor и BeanDefinitionRegistryPostProcessor
Вы можете узнать из введения "BeanDefinition Acquisition"BeanDefinitionRegistry
дляBeanDefinition
зарегистрироваться наBeanFactory
середина,GenericApplicationContext
и DefaultListableBeanFactory
реализовать этот интерфейс,GenericApplicationContext
Реализация в вызывается напрямуюbeanFactory
реализация.
BeanFactoryPostProcessor
иBeanDefinitionRegistryPostProcessor
и BeanPostProcessor
Похожие, но из их наименования видно, что цели разные, а именноBeanFactory
и BeanDefinitionRegistry:
1 BeanFactoryPostProcessor
Обратные вызовы дают разработчикам возможностьBeanFactory
В случае уже инициализированногоBeanFactory
Переопределить некоторые свойства , илиbeanDefinitionMap
середина BeanDefinition
модифицировать.
2BeanDefinitionRegistryPostProcessor
Это позволяет разработчикам продолжать добавлятьBeanDefinition
прибытьBeanFactory
середина.
Конкретная логика вinvokeBeanFactoryPostProcessors
В реализации здесь сначала будут реализованы всеBeanFactoryPostProcessors
Бин создает экземпляр, а затем вызывает свой метод обратного вызова (postProcessBeanDefinitionRegistry
или postProcessBeanFactory
метод).
Существуют определенные правила приоритета для создания экземпляра и обратного вызова этой части компонента.PriorityOrdered
унаследовано отOrdered
интерфейс, реализующийPriorityOrdered
из BeanDefinitionRegistryPostProcessor
будут созданы и вызваны первыми, а затем будут вызваны те же самые правила для реализацииBeanFactoryPostProcessor
Бин:PriorityOrdered
> Ordered
> не реализует заказанный
существует registerBeanPostProcessors
способBeanPostProcessor
У экземпляра также есть это правило приоритета:PriorityOrdered
> Ordered
> не реализует Заказ >MergedBeanDefinitionPostProcessor
ApplicationEventMulticaster
существуетinitApplicationEventMulticaster
Центральная встречаApplicationEventMulticaster
Инициализировать: сначала проверьте, есть ли ужеApplicationEventMulticaster
из BeanDefinition
(существует beanDefinitionMap
Зарегистрируйтесь), если есть, позвольте контейнеру создать экземпляр, если нет, используйте фреймворк по умолчанию.ApplicationEventMulticaster
(которыйSimpleApplicationEventMulticaster
), сначала создается экземпляр, а затем регистрируется в контейнере (MessageSource
существуетinitMessageSource
метод также инициализируется таким же образом).
Начальное место отправки события оборачивает событие какApplicationEvent
, и поApplicationEventPublisher
подчинятьсяApplicationEventMulticaster
,ApplicationEventMulticaster
будет транслировать событие наApplicationListener
, который обрабатывает окончательное распределение.
AbstractApplicationEventMulticaster
серединаapplicationListeners(
ФактическиLinkedHashSet<ApplicationListener>)
Переменная содержит все широковещательные приемники,registerListeners
метод преобразует всеApplicationListener
добавить в эту коллекцию.
finishRefresh
метод имеет паруContextRefreshedEvent
Трансляция события может быть использована в качестве справочной, а финальное событие будет отправлено поmulticastEvent
Метод обработки:
SimpleApplicationEventMulticaster.multicastEvent
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
Итак, как мы можем получить это в нашем собственном BeanApplicationEventPublisher
Шерстяная ткань?ApplicationContext
определяется следующим образом:
ApplicationContext
:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
видимыйApplicationContext
наследовать ApplicationEventPublisher
, Это означает, чтоAbstractApplicationContext
такжеApplicationEventPublisher
. в нашем собственном компоненте путем реализацииApplicationEventPublisherAware
, мы можем пройтиsetApplicationEventPublisher
получить обратный вызовApplicationEventPublisher
.
Выше мы упомянули многие весенниеAware
черезBeanPostProcessor
осуществленный,ApplicationEventPublisherAware
Не исключение:
ApplicationContextAwareProcessor
:
@Override
@Nullable
public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {
// ...
if (bean instanceof Aware) {
if (bean instanceof EnvironmentAware) {
((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
}
if (bean instanceof EmbeddedValueResolverAware) {
((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
}
if (bean instanceof ResourceLoaderAware) {
((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
}
if (bean instanceof ApplicationEventPublisherAware) {
((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
}
if (bean instanceof MessageSourceAware) {
((MessageSourceAware) bean).setMessageSource(this.applicationContext);
}
if (bean instanceof ApplicationContextAware) {
((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
}
}
// ...
}
Контейнер IOC вызывается при создании экземпляра нашего bean-компонентаApplicationContextAwareProcessor
.postProcessBeforeInitialization
метод, который проверяет наш бин, если наш бин реализуетApplicationEventPublisherAware
, то он перезвонитsetApplicationEventPublisher
метод будетapplicationContext
(которыйApplicationEventPublisher
) к нам, и мы можем опубликовать событие.
BeanFactory.getBean
BeanFactory
несколько перегруженныхgetBean
Метод - это место, где bean-компонент окончательно создается,registerBeanPostProcessors
, invokeBeanFactoryPostProcessors
и finishBeanFactoryInitialization
Все методы вызывают метод getBean для создания экземпляров некоторых конкретных компонентов.
finishBeanFactoryInitialization
позвонивBeanFactory
из preInstantiateSingletons
Создайте экземпляр одноэлементного компонента.BeanFactory
и BeanDefinition
Оба имеют концепцию родителя и дочернего элемента.Когда дочерний элемент не может найти указанный компонент, он всегда будет искать (родительский) и создавать его экземпляр при обнаружении.
Суммировать
Шаги запуска контейнера Spring IOC можно резюмировать следующим образом: 1 Инициализировать ApplicationContext Инициализация и проверка свойств среды, запись времени запуска и соответствующие настройки флагов, инициализация событий приложения и слушателей.
2 Подготовьте BeanDefinition в контейнере (бины с нетерпеливой инициализацией)
правильно BeanDefinition
разбор, сканирование и регистрацияBeanDefinition
Сканирование и регистрацию 。 можно условно разделить на два типа: XML и аннотацию.Компоненты, используемые в этих двух методах, различны, и время этого шага также может быть на первом плане.
3 Инициализировать BeanFactory Подготовьте BeanFactory для использования ApplicationContext, создайте экземпляр Bean, который будет использоваться следующим, подготовьте ресурсы и задайте свойства.
4 Регистрация BeanPostProcessors BeanPostProcessors являются ключевыми компонентами для расширения, которые необходимо зарегистрировать на этом этапе. Их можно разделить на два типа: один предоставляется пользователем Framework для конкретных бизнес-функций, а другой предоставляется разработчиками рамок, используя для расширения структуры рамок. Функциональность.
5 звонокBeanDefinitionRegistryPostProcessor
BeanDefinitionRegistryPostProcessor
является улучшением функции, на этом этапе можно добавить новыеBeanDefinition
прибытьBeanFactory
середина.
6 звонокBeanFactoryPostProcessor
BeanFactoryPostProcessor
Это расширение функции.На этом шаге вы можете перезаписать свойства BeanFactory, которые были инициализированы, или изменить зарегистрированныеBeanFactory
из BeanDefinition
.
7 ИнициализацияMessageSource
и ApplicationEventMulticaster
MessageSource
для обработки интернационализированных ресурсов,ApplicationEventMulticaster
Является распространителем событий приложения, используемым для распространения событий приложения среди прослушивателей.
8 Инициализировать другие bean-компоненты и выполнить другую инициализацию контекста В основном используется для расширения
9 РегистрацияApplicationListene
будет ApplicationListene
зарегистрироваться наBeanFactory
, для последующего распределения событий
10 Создайте оставшиеся синглтоны Bean Все шаги с 4 по 9 создают экземпляры некоторых специальных bean-компонентов, здесь необходимо создать экземпляры всех оставшихся одноэлементных bean-компонентов.
11 Запуск завершен Переработка ресурсов, отправка события «обновление завершено».