Анализ процесса запуска контейнера Spring IOC

Spring

Анализ процесса запуска контейнера Spring IOC

При использовании Spring XML и аннотации являются двумя наиболее часто используемыми методами настройки.Хотя это два совершенно разных метода настройки, для контейнера IOC разница между двумя методами заключается в основном вBeanDefinitionна анализ. Для процесса запуска основного контейнера он остается прежним.

AbstractApplicationContextизrefreshМетод реализует основную логику запуска IOC-контейнера, а ключевые шаги в процессе запуска также могут соответствовать независимым методам в исходном коде. Далее сAbstractApplicationContextКласс реализацииClassPathXmlApplicationContextMain и сравните его другой класс реализации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.

Spring ApplicationContext 继承图.jpg
Дерево наследования ApplicationContext (HD большая картинка)

Spring BeanFactory 继承图.jpg
Дерево наследования BeanFactory (HD большая картинка)

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.

Spring Context refresh 主流程时序图_看图王.jpg
HD большая картинка

BeanPostProcessor

BeanPostProcessorИнтерфейс позволяет разработчику получить обратный вызов, когда контейнер IOC создает экземпляр bean-компонента (postProcessAfterInitializationи postProcessBeforeInitializationметод). Многие уведомления внутри фреймворка Spring (Aware) реализуется через этот интерфейс, напримерApplicationContextAwareProcessorServletContextAwareProcessor, их реализация будет в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-компонент окончательно создается,registerBeanPostProcessorsinvokeBeanFactoryPostProcessorsи 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 Запуск завершен Переработка ресурсов, отправка события «обновление завершено».