1. Старое правило: сначала сравните несколько мотыльков.
Как бэкенд-программист, часто использующий Spring, Сяобиан давно хотел досконально разобраться во всей структуре Spring! Но в целом он очень большой, и все схемы наследования очень сложны.Кроме того, практика редактора еще неглубока, что делает его бессильным. Тем не менее, человек должен быть определен в этом мире.Сегодня мы начнем с инициализации контейнера Spring IOC.Даже если мы не можем полностью понять всю структуру Spring, это не стыдно, потому что редактор начал, держись, и мы сможем победить!
Вот несколько советов перед чтением:
- 1. Читать анализ исходного кода очень скучно, но раз уж вы зашли, то тоже должны разбираться в этом деле, и я надеюсь, что это краткое изложение сможет вас вдохновить.
- 2. Энергии вперед, статья может быть очень длинной, с картинками и текстами.
- 3. Перед чтением рекомендуется иметь представление о шести принципах связанных шаблонов проектирования и проектирования программного обеспечения.Редактор будет чередовать их в тексте.
- 4. Редактор на четвертом курсе, а познания у него еще поверхностные, и ему нравится специализироваться на исследованиях.Если вы обнаружите, что мнение статьи неверное или отличается от вашего мнения, пожалуйста, укажите и сообщите в комментарии площадь!
- 5. Рекомендуется выполнять отладку и трассировку в среде IDE при чтении статьи.
- 6. Все UML-диаграммы в статье генерируются автоматически с помощью идеи. Конкретный метод генерации:
选中一个类名,先ctrl+shift+alt+U,再ctrl+alt+B,然后回车即可
2. О чем будет рассказываться в статье?
Немного, всего одна строка кода, как показано ниже:
Это предложение представляет собой код, инициализированный Spring. Хотя это всего одно предложение кода, в нем много содержания!
3. Каковы компоненты IOC контейнера Spring?
Таким образом, редактор сначала разъясняет идею шаг за шагом:
- 1. В приведенном выше коде есть файл с именем
applicationContext.xml
, это файл ресурсов, так как нашbean
В нем все настроено и определено, поэтому Spring должен сделать этот файл.读取并解析
Бар! Итак, в Spring есть модуль, называемыйResource
Модуль, как следует из названия,资源
Что ж! для всех ресурсовxml、txt、property
Абстракция других файловых ресурсов. О пареResource
Для получения дополнительной информации вы можете обратиться к следующим двум статьям:
Анализ файла ресурсов Spring и применение шаблона стратегии (Li Gang)
Ниже приведена диаграмма классов, сгенерированная редактором.(图片有点大,不知道会不会不清晰,如果不清晰可以按照上面说的idea生成方法去生成即可)
:
можно увидетьResource
Это корневой интерфейс всей системы. Нажмите на исходный код, чтобы увидеть, что он определяет многие策略方法
, потому что используется策略模式
Преимущество использования этого шаблона проектирования заключается в том, что策略接口/类
Определена одна и та же стратегия, и разные подклассы имеют разные реализации конкретной стратегии.Когда клиент вызывает, передается конкретный объект реализации.比如UrlResource或者FileSystemResource
давать策略接口/类Resource
Вот и все!
все策略
следующее:
- 2. Вышеупомянутое, что среда Spring использует абстракцию различных ресурсов.
策略模式
, тогда возникает вопрос, теперь, когда есть что-то, представляющее ресурс, как загрузить ресурс? Итак, есть следующееResourceLoader
Компонент, отвечающий за загрузку ресурсов Spring, ресурсы относятся кxml
,properties
и другие файловые ресурсы, возвращают соответствующий типResource
объект. . Схема UML выглядит следующим образом:
Как видно из диаграммы UML выше,ResourceLoader
компоненты на самом делеResource
Компоненты похожи, все они являются корневым интерфейсом, соответствующим различным реализациям подкласса, например, загрузка ресурсов из файловой системы, вы можете использоватьFileSystemResourceLoader
, загружается изServletContext
ресурсы контекста, вы можете использоватьServletContextResourceLoader
.
И самое главное, как вы можете видеть на картинке выше,ApplicationContext
,AbstractApplication
реализуетсяResourceLoader
Да что это значит? Опишите контекст нашего приложенияApplicationContext
Имеет возможность загружать ресурсы, что также объясняет, почему вы можете пройти вString resource path
даватьClassPathXmlApplicationContext("applicationContext.xml")
Причина, по которой вы можете получить ресурс файла xml! Это понятно? Ницца!
- 3. Вышеупомянутые два пункта были упомянуты, хорошо! Теперь, когда у нас есть загрузчик
ResourceLoader
, также есть описание ресурсаResource
, но мы объявили в xml файле<bean/>
Как теги представлены в Spring? Обратите внимание, что это верно толькоbean
определение, а не то, как<bean/>
преобразовать вbean
объект. Я думаю, что это должно быть легко понять! как вы хотите обозначить студентаStudent
, то вы должны объявить класс в программеStudent
Бар! Данные о студентах взяты изexcel
импорт, или когда программа запускаетсяnew
из или изxml
Неважно, загрузите ли вы его в<bean/>
Также нужно сделать определение весной! Итак, мы представляемBeanDefinition
Компоненты диаграммы UML следующие:
Диаграмма UML поясняется ниже:
Сначала в файле конфигурации<bean/>
Отметить нашимBeanDefinition
переписка один на один,<bean>
тег элемента имеетclass
,scope
,lazy-init
и другие свойства конфигурации,BeanDefinition
предоставляет соответствующиеbeanClass
,scope
,lazyInit
Атрибуты.
в
RootBeanDefinition
наиболее часто используемый класс реализации, соответствующий общему<bean>
тег элемента,GenericBeanDefinition
Это я2.5
недавно добавлено позжеbean
Класс определения атрибута конфигурации файла — это универсальный класс обслуживания. Родитель может быть определен в файле конфигурации<bean>
И ребенок<bean>
,отец<bean>
использоватьRootBeanDefinition
значит, в то время как суб<bean>
использоватьChildBeanDefiniton
выражается без родителя<bean>
из<bean>
просто используйтеRootBeanDefinition
Выражать.AbstractBeanDefinition
Абстрагируйте общую информацию о классе обоих.Spring
пройти черезBeanDefinition
в файле конфигурации<bean>
Информация о конфигурации преобразуется во внутреннее представление контейнера, и этиBeanDefiniton
зарегистрироваться наBeanDefinitonRegistry
середина.Spring
контейнерBeanDefinitionRegistry
Это какSpring
Находящаяся в памяти база данных с информацией о конфигурации, в основном в видеmap
сохраняется в виде , а последующие операции осуществляются непосредственно изBeanDefinitionRegistry
прочитать информацию о конфигурации. В целом,BeanDefinition
Он загружается и анализируется только при запуске контейнера. Если контейнер не будет обновлен или перезапущен, эта информация не изменится. Конечно, если у пользователя есть особые потребности, ее также можно настроить программно во время выполнения.BeanDefinition
Определение.
- 4. С погрузчиком
ResourceLoader
, также есть описание ресурсаResource
, также имеют правоbean
определение, мы не можем не спросить, нашResource
Как ресурсы превращаются в насBeanDefinition
А как насчет? Итак, мы представилиBeanDefinitionReader
Компоненты, читатель! Это механизм чтения.Схема UML выглядит следующим образом:
Как видно из вышеизложенного, Spring абстрагирует читателя, а конкретные функции передаются его подклассам для реализации.Разные реализации соответствуют разным классам, напримерPropertiedBeanDefinitionReader
,XmlBeanDefinitionReader
Соответственно анализируется из ресурса свойства и xml вBeanDefinition
.
На самом деле преобразование прочитанных данных во внутренние объекты является не только собственностью Spring, например: парсер Dom4j
SAXReader reader = new SAXReader(); Document doc = reader.read(url.getFile());
//url — это объект URLResource Строго говоря, это система чтения, предназначенная для чтения и преобразования унифицированных объектов данных ресурсов в соответствующие внутренние объекты.
- 5. Хорошо! В принципе все компоненты почти готовы! Кстати, есть еще один компонент, у вас есть
BeanDefinition
, вы также должны зарегистрировать их на заводе, поэтому при использованииgetBean()
метод только тогда, когда фабрика знает, что вам вернуть. Есть еще одна проблема, так как мы хотим сохранить регистрацию этихbean
, Должна быть структура данных, чтобы действовать как контейнер! Да, это одинMap
, размещено нижеBeanDefinitionRegistry
Реализация, называемаяSimpleBeanDefinitionRegistry
Исходное изображение:
BeanDefinitionRegistry
Схема UML выглядит следующим образом:
Как видно из рисунка,BeanDefinitionRegistry
Есть три реализации по умолчанию, а именноSimpleBeanDefinitionRegistry
,DefaultListableBeanFactory
,GenericApplicationContext
,вSimpleBeanDefinitionRegistry
,DefaultListableBeanFactory
Оба содержат карту, что означает, что два класса реализации сохраняют компонент. иGenericApplicationContext
держитDefaultListableBeanFactory
Ссылка на объект используется для получения внутри соответствующей карты.
существуетDefaultListableBeanFactory
середина
существуетGenericApplicationContext
середина
- 6. Пять пунктов, упомянутых выше, в основном можно увидеть
ApplicationContext
Контекст в основном проходит через все части прямо или косвенно, поэтому мы обычно называем его容器
,Кроме,ApplicationContext
также имеет в дополнение кbean容器
В дополнение к этой роли, он также включает в себя получение такой информации, как параметры среды для запуска всей программы (например, версия JDK, jre и т. д.) Фактически, эта часть Spring также была соответствующим образом инкапсулирована, что называетсяEnviroment
, Давайте последуем за затмением Xiaobian и вместе отладим проект инициализации контейнера!
В-четвертых, практика является единственным стандартом для проверки правды
студенческий классStudent.java
следующее:
package com.wokao666;
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student(int id, String name, int age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
public Student() {
super();
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", age=" + age + "]";
}
}
существуетapplication.xml
конфигурация, дваbean
:
<bean id="stu1" class="com.wokao666.Student">
<property name="id" value="1"></property>
<property name="name" value="xiaoming"></property>
<property name="age" value="21"></property>
</bean>
<bean id="stu2" class="com.wokao666.Student">
<property name="id" value="2"></property>
<property name="name" value="xiaowang"></property>
<property name="age" value="22"></property>
</bean>
Хорошо, давайте сделаем брейкпоинт для кода в самом начале (Breakpoint
):
первый шаг:急切地加载ContextClosedEvent类,以避免在WebLogic 8.1中的应用程序关闭时出现奇怪的类加载器问题。
Не беспокойтесь слишком много об этом шаге!
Шаг 2:既然是new ClassPathXmlApplicationContext()
Тогда вызовите конструктор!
третий шаг:
четвертый шаг:
Хорошо, давайте выполним шаги в шаге 3super(parent)
, а затем в сочетании с диаграммой UML шестого пункта в третьем разделе выше, чтобы отслеживать шаг за шагом, и тогда мы приходим кAbstractApplicationContext
этого метода:
затем внутриresourcePatternResolver
Что такое тип? К какой части из 6 шагов, упомянутых в разделе 3, относится? По трассировке видно, что его типResourcePatternResolver
тип, покаResourcePatternResolver
снова унаследовалResourceLoader
интерфейс, так что он относится к модулю ресурсов загрузки.Если непонятно, давайте посмотримResourcePatternResolver
Исходный код может быть, как показано ниже:
Правильно! не только унаследовалResourceLoader
интерфейс и определить только одинgetResources()
метод возвратаResource[]
Сбор ресурсов. Кроме того, этот интерфейс также использует策略模式
, его конкретная реализация находится в классе реализации, ладно! Взгляните на диаграмму UML, чтобы узнать!
PathMatchingResourcePatternResolver
Как насчет этого класса реализации! Он используется для объяснения различных ресурсов пути.Например, путь ресурса, по которому вы проходите, может быть обычным.url
, или возможноclasspath*
Ему переданы все префиксы.
ServletContextResourcePatternResolver
Этот класс реализации, как следует из названия, используется для загрузкиServlet
Контекстный, обычно используемый в Интернете.
пятый шаг:
Рядом с методом четвертого шага, когда мы еще не вошли в метод четвертого шага, мы будемAbstractApplicationContext
создать экземпляр, когдаthis
Некоторые свойства объекта инициализируются(如日志对象)
,Как показано ниже:
затем введитеgetResourcePatternResolver()
метод:
Четвертый шаг сказал:PathMatchingResourcePatternResolver
Он используется для работы с различными путями ресурсов, как с этим бороться, давайте сначала посмотрим!
Если найдено, консоль напечатает找到用于OSGi包URL解析的Equinox FileLocator
бревно. Нет печати, очевидно, не могу найти!
запустить полный возвратsetParent()
метод.
Шаг 6:
Если родитель неnull
, то родитель совпадает с текущимthis
Применить слияние контекста. Очевидно, что этот шаг ничего не делает!parent
очевидноnull
, Тогда не сливайте! Все еще пользуюсь текущимthis
среда г.
Подводя итог: первые шесть шагов в основном делают две вещи:
- 1. Инициализировать соответствующую контекстную среду, т. е. инициализировать
ClassPathXmlApplicationContext
пример - 2. Получите
resourcePatternResolver
объект, что удобно для разбора ресурсов седьмого шага вResource
объект
Шаг 7:
Седьмой шаг возвращает к коду в начале третьего шага, потому что мы выполнили предыдущие 6 шагов.super(parent)
отслеживание. покажи намsetConfigLocation()
Что за метод~
/**
* Set the config locations for this application context.//未应用上下文设置资源路径
* <p>If not set, the implementation may use a default as appropriate.//如果未设置,则实现可以根据需要使用默认值。
*/
public void setConfigLocations(String... locations) {
if (locations != null) {//非空
Assert.noNullElements(locations, "Config locations must not be null");//断言保证locations的每个元素都不为null
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();//去空格,很好奇resolvePath做了什么事情?
}
}
else {
this.configLocations = null;
}
}
ВходитьresolvePath()
Смотри как:
/**
* 解析给定的资源路径,必要时用相应的环境属性值替换占位符,应用于资源路径配置。
* Resolve the given path, replacing placeholders with corresponding
* environment property values if necessary. Applied to config locations.
* @param path the original file path
* @return the resolved file path
* @see org.springframework.core.env.Environment#resolveRequiredPlaceholders(String)
*/
protected String resolvePath(String path) {
return getEnvironment().resolveRequiredPlaceholders(path);
}
ВходитьgetEnvironment()
Взгляни:
/**
* {@inheritDoc}
* <p>If {@code null}, a new environment will be initialized via
* {@link #createEnvironment()}.
*/
@Override
public ConfigurableEnvironment getEnvironment() {
if (this.environment == null) {
this.environment = createEnvironment();
}
return this.environment;
}
ВходитьcreateEnvironment()
, метод, мы видим здесь, что новыйStandardEnviroment
объект, этоEnvironment
Класс реализации представляет среду, в которой работает контейнер, например среду JDK, среду Servlet, среду Spring и т. д. Каждая среда имеет свои собственные данные конфигурации, такие какSystem.getProperties()
,System.getenv()
Подождите, пока вы не сможете получить данные среды JDK;ServletContext.getInitParameter()
Вы можете получить данные конфигурации среды сервлета и т. д., что означает, что Spring абстрагируетEnvironment
для представления конфигурации среды.
СгенерированоStandardEnviroment
Объект ничего не содержит, только стандартное окружение, и все свойства имеют значения по умолчанию.
Резюме: для входящихpath
Сделать разрешение пути
Шаг 8:这一步是重头戏
Подводя итог: пока у нас есть следующие примеры:
Теперь код переходит к следующему рисункуrefresh()
метод:
Взгляните, каково содержание этого метода?
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 刷新前准备工作,包括设置启动时间,是否激活标识位,初始化属性源(property source)配置
prepareRefresh();
// 创建beanFactory(过程是根据xml为每个bean生成BeanDefinition并注册到生成的beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
//准备创建好的beanFactory(给beanFactory设置ClassLoader,设置SpEL表达式解析器,设置类型转化器【能将xml String类型转成相应对象】,
//增加内置ApplicationContextAwareProcessor对象,忽略各种Aware对象,注册各种内置的对账对象【BeanFactory,ApplicationContext】等,
//注册AOP相关的一些东西,注册环境相关的一些bean
prepareBeanFactory(beanFactory);
try {
// 模板方法,为容器某些子类扩展功能所用(工厂后处理器)这里可以参考BeanFactoryPostProcessor接口的postProcessBeanFactory方法
postProcessBeanFactory(beanFactory);
// 调用所有BeanFactoryPostProcessor注册为Bean
invokeBeanFactoryPostProcessors(beanFactory);
// 注册所有实现了BeanPostProcessor接口的Bean
registerBeanPostProcessors(beanFactory);
// 初始化MessageSource,和国际化相关
initMessageSource();
// 初始化容器事件传播器
initApplicationEventMulticaster();
// 调用容器子类某些特殊Bean的初始化,模板方法
onRefresh();
// 为事件传播器注册监听器
registerListeners();
// 初始化所有剩余的bean(普通bean)
finishBeanFactoryInitialization(beanFactory);
// 初始化容器的生命周期事件处理器,并发布容器的生命周期事件
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// 销毁已创建的bean
destroyBeans();
// 重置`active`标志
cancelRefresh(ex);
throw ex;
}
finally {
//重置一些缓存
resetCommonCaches();
}
}
}
Вот хочу сказать, этоrefresh()
Метод на самом деле является методом шаблона.Многие методы реализованы разными классами реализации, но сам класс также реализует некоторые из этих методов, и эти реализованные методы не могут быть переписаны подклассами, такими как:prepareRefresh()
метод. Дополнительные шаблоны проектирования методов шаблонов см. в моей предыдущей статье.Расскажите о моем понимании шаблона проектирования «метод шаблона» (Шаблон)
войти первымprepareRefresh()
метод:
/**
* Prepare this context for refreshing, setting its startup date and
* active flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();//设置容器启动时间
this.closed.set(false);//容器关闭标志,是否关闭?
this.active.set(true);//容器激活标志,是否激活?
if (logger.isInfoEnabled()) {//运行到这里,控制台就会打印当前容器的信息
logger.info("Refreshing " + this);
}
// 空方法,由子类覆盖实现,初始化容器上下文中的property文件
initPropertySources();
//验证标记为必需的所有属性均可解析,请参阅ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();
//允许收集早期的ApplicationEvents,一旦多播器可用,即可发布...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
Вывод консоли:
三月 22, 2018 4:21:13 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@96532d6: startup date [Thu Mar 22 16:21:09 CST 2018]; root of context hierarchy
Шаг 9:
ВходитьobtainFreshBeanFactory()
метод:
/**
* 告诉子类刷新内部bean工厂(子类是指AbstractApplicationContext的子类,我们使用的是ClassPathXmlApplicationContext)
* Tell the subclass to refresh the internal bean factory.
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();//刷新Bean工厂,如果已经存在Bean工厂,那就关闭并销毁,再创建一个新的bean工厂
ConfigurableListableBeanFactory beanFactory = getBeanFactory();//获取新创建的Bean工厂
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);//控制台打印
}
return beanFactory;
}
ВходитьrefreshBeanFactory()
метод:
/**
* 该实现执行该上下文的基础Bean工厂的实际刷新,关闭以前的Bean工厂(如果有的话)以及为该上下文的生命周期的下一阶段初始化新鲜的Bean工厂。
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {//如果已有bean工厂
destroyBeans();//销毁
closeBeanFactory();//关闭
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();//创建一个新的bean工厂
beanFactory.setSerializationId(getId());//为序列化目的指定一个id,如果需要,可以将此BeanFactory从此id反序列化回BeanFactory对象。
//定制容器,设置启动参数(bean可覆盖、循环引用),开启注解自动装配
customizeBeanFactory(beanFactory);
////将所有BeanDefinition载入beanFactory中,此处依旧是模板方法,具体由子类实现
loadBeanDefinitions(beanFactory);
//beanFactory同步赋值
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
Резюме: основная работа этого шага состоит в том, чтобы определить, существует ли beanfactory перед обновлением контейнера.Если да, то уничтожьте старую beanfactory, затем уничтожьте и создайте новую beanfactory, чтобы вернуться в контейнер, и в то же время XML-файлBeanDefinition
Зарегистрируйтесь на beanfactory.如果不太清楚可以回过头看看我们的第三节第5点内容
Шаг 10:
в девятый шагloadBeanDefinitions(beanFactory)
путьtake a look
:
/**
* 使用XmlBeanDefinitionReader来加载beandefnition,之前说过使用reader机制加载Resource资源变为BeanDefinition对象
* Loads the bean definitions via an XmlBeanDefinitionReader.
* @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader
* @see #initBeanDefinitionReader
* @see #loadBeanDefinitions
*/
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader对象
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 使用当前上下文Enviroment中的Resource配置beanDefinitionReader,因为beanDefinitionReader要将Resource解析成BeanDefinition嘛!
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
//初始化这个reader
initBeanDefinitionReader(beanDefinitionReader);
//将beandefinition注册到工厂中(这一步就是将bean保存到Map中)
loadBeanDefinitions(beanDefinitionReader);
}
Вывод консоли:
三月 22, 2018 5:09:40 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [applicationContext.xml]
Шаг 11:
ВходитьprepareBeanFactory(beanFactory)
метод:
//设置bean类加载器
//设置Spring语言表达式(SpEL)解析器
//扫描ApplicationContextAware bean
//注册类加载期类型切面织入(AOP)LoadTimeWeaver
//为各种加载进入beanFactory的bean配置默认环境
Шаг 12:
postProcessBeanFactory(beanFactory)
метод:
postProcessBeanFactory
Также в качестве шаблонного метода конкретная реализация предоставляется подклассом, и подкласс может иметь свою собственную специальную паруBeanDefinition
методы постобработки, т.е. подклассы могут генерировать эту пару передBeanDefinition
,Сейчасbean
Переобработка метаданных. например, изменениеbean
изid/name
Атрибуты,scope
Атрибуты,lazy-init
свойства и т. д.
Шаг тринадцатый:
invokeBeanFactoryPostProcessors(beanFactory)
метод:
Этот метод вызывает всеBeanFactoryPostProcessor
, это интерфейс, класс, реализующий этот интерфейс, должен переопределитьpostProcessBeanFactory()
Этот метод, видно, что этот метод такой же, как метод на двенадцатом шаге, но в качестве интерфейса разработчикам больше предоставляется возможность генерироватьBeanDefinition
Для обработки разработчик предоставляет логику обработки.
Шаг 14:
Остальные методы в основном похожи初始化消息处理源
,初始化容器事件
,注册bean监听器到事件传播器上
и, наконец, завершает обновление контейнера.
V. Резюме
Поздравляю, я наконец закончил писать, и поздравляю вас, вы дочитали.
Я восхищаюсь собой за то, что так долго подвожу итоги и публикую Причина, по которой я хочу подвести итоги, заключается в том, что редактор все еще согласен好记性不如烂笔头
утверждение.
Если не помнишь, то через некоторое время забудешь, а если запишешь, то через некоторое время забудешь! Разница в том, что если вы его забудете, то сможете вернуться и вспомнить его за короткий промежуток времени, проверить на наличие упущений и сократить затраты на обучение.
Кроме того, я думаю, что мой анализ не идеален, и в нем много недостатков, поэтому я опубликую все статьи, которые я написал, чтобы обсудить и обменяться со всеми.У Шаньтоуского университета есть школьный девиз, который очень хорошо говорит об этом, то есть: знания предназначены для обмена Да, благодаря обмену знания могут стать связующим звеном между прошлым и будущим.
Теперь давайте разберемся с процессом инициализации Spring:
- 1. Сначала инициализируйте контекст и сгенерируйте
ClassPathXmlApplicationContext
объект, получениеresourcePatternResolver
объект будетxml
анализируется вResource
объект. - 2. Используйте контекст и ресурс, сгенерированные 1, для инициализации фабрики, синтаксического анализа ресурса в определение bean-компонента, а затем зарегистрируйте определение bean-компонента в beanfactory.
Друзья, если вы найдете какие-либо недостатки, пожалуйста, прокомментируйте и сообщите в редакцию, и общайтесь друг с другом!