Процесс инициализации IOC контейнера Spring --- наконец-то резюмирован сегодня

задняя часть Spring Шаблоны проектирования UML
Процесс инициализации IOC контейнера Spring --- наконец-то резюмирован сегодня

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 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, например: парсер Dom4jSAXReader reader = new SAXReader(); Document doc = reader.read(url.getFile());//url — это объект URLResource Строго говоря, это система чтения, предназначенная для чтения и преобразования унифицированных объектов данных ресурсов в соответствующие внутренние объекты.

  • 5. Хорошо! В принципе все компоненты почти готовы! Кстати, есть еще один компонент, у вас естьBeanDefinition, вы также должны зарегистрировать их на заводе, поэтому при использованииgetBean()метод только тогда, когда фабрика знает, что вам вернуть. Есть еще одна проблема, так как мы хотим сохранить регистрацию этихbean, Должна быть структура данных, чтобы действовать как контейнер! Да, это одинMap, размещено нижеBeanDefinitionRegistryРеализация, называемаяSimpleBeanDefinitionRegistryИсходное изображение:

BeanDefinitionRegistryСхема UML выглядит следующим образом:

Как видно из рисунка,BeanDefinitionRegistryЕсть три реализации по умолчанию, а именноSimpleBeanDefinitionRegistry,DefaultListableBeanFactory,GenericApplicationContextSimpleBeanDefinitionRegistry,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.

Друзья, если вы найдете какие-либо недостатки, пожалуйста, прокомментируйте и сообщите в редакцию, и общайтесь друг с другом!