Анализ процесса запуска контейнера 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.
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 Запуск завершен Переработка ресурсов, отправка события «обновление завершено».