Анализ исходного кода Spring

Java

Другие основные статьи по Java:
Базовое изучение Java (справочник)


Исходный код Spring слишком велик, для нетехнического человека первое время будет очень сложно, поэтому я решил читать его модуль за модулем, и записал те статьи, которые показались мне очень хорошими в процессе обучения. Рекомендуется сначала прочитать рекомендуемый блог, а затем прочитать мое дополнение.Текущая версия Spring 4.3.18

Spring читает пользовательский разбор XML-файла

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

фокус

Процесс запуска всего контейнера находится в методе шаблона refresh() класса AbstractApplicationContext.

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();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

В центре внимания следующего объясненияobtainFreshBeanFactory()Сюда.

Рекомендуемый блог

  • Тщательно изучите контейнер Spring с помощью чтения исходного кода и диаграмм последовательности.: порядок чтения этой статьи очень хороший. Она соответствует порядку выполнения кода, и есть диаграмма последовательности, помогающая в обучении. Тем не менее, я все еще немного сбит с толку, читая эту статью, главным образом потому, что она не достаточно для некоторых подробностей, и резюме является относительно грубым. Его следует изучать вместе со следующими статьями.
  • Анализ исходного кода Spring Ioc (1) -- Загрузка контейнера Spring Ioc: В этой серии четыре главы, и детали относительно ясны. Он разделен на три модуля для объяснения, и есть много резюме и народных описаний методов, которые легче понять. Недостаток в том, что порядок недостаточно хорош, часто перескакивает с одного места на другое.

Суммировать

Я потратил время, чтобы перерисовать диаграмму последовательности, но процесс был слишком долгим, а качество изображения всего процесса было не очень хорошим. Поэтому я нарисовал и общую, и локальную временные диаграммы, чтобы все могли сравнить.

时序图(整)

时序图1

时序图2

时序图3

时序图4

Ниже приводится текстовое дополнение технологического процесса всей схемы последовательности:

SpringMain->ClassPathXmlApplicationContext: new ClassPathXmlApplicationContext("applicationContext.xml");
ClassPathXmlApplicationContext->AbstractRefreshableConfigApplicationContext: setConfigLocations()
AbstractRefreshableConfigApplicationContext->ClassPathXmlApplicationContext: return
ClassPathXmlApplicationContext->AbstractApplicationContext: refresh()
AbstractApplicationContext->AbstractApplicationContext: obtainFreshBeanFactory()
AbstractApplicationContext->AbstractRefreshableApplicationContext: refreshBeanFactory()
AbstractRefreshableApplicationContext->AbstractXmlApplicationContext: loadBeanDefinitions()
AbstractXmlApplicationContext->AbstractXmlApplicationContext: loadBeanDefinitions()
AbstractXmlApplicationContext->AbstractBeanDefinitionReader: reader.loadBeanDefinitions(configLocations);
AbstractBeanDefinitionReader->AbstractBeanDefinitionReader: counter += loadBeanDefinitions(location);
AbstractBeanDefinitionReader->AbstractBeanDefinitionReader: return loadBeanDefinitions(location, null);
AbstractBeanDefinitionReader->XmlBeanDefinitionReader: int loadCount = loadBeanDefinitions(resource);
XmlBeanDefinitionReader->XmlBeanDefinitionReader: doLoadBeanDefinitions()
XmlBeanDefinitionReader->XmlBeanDefinitionReader: registerBeanDefinitions()
XmlBeanDefinitionReader->DefaultBeanDefinitionDocumentReader: registerBeanDefinitions(doc, createReaderContext(resource));
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: doRegisterBeanDefinitions()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: parseBeanDefinitions()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: parseDefaultElement()
DefaultBeanDefinitionDocumentReader->DefaultBeanDefinitionDocumentReader: processBeanDefinition()
DefaultBeanDefinitionDocumentReader->BeanDefinitionParserDelegate: parseBeanDefinitionElement()
BeanDefinitionParserDelegate->BeanDefinitionParserDelegate: parseBeanDefinitionElement(ele, beanName, containingBean);
note right of BeanDefinitionParserDelegate: parsePropertyElements(ele, bd);
BeanDefinitionParserDelegate->DefaultBeanDefinitionDocumentReader: return new BeanDefinitionHolder
DefaultBeanDefinitionDocumentReader->BeanDefinitionParserDelegate: decorateBeanDefinitionIfRequired
DefaultBeanDefinitionDocumentReader->BeanDefinitionReaderUtils: registerBeanDefinition
BeanDefinitionReaderUtils->DefaultListableBeanFactory: registerBeanDefinition
note right of DefaultListableBeanFactory: this.beanDefinitionMap.put(beanName, beanDefinition);
note right of DefaultListableBeanFactory: this.beanDefinitionNames.add(beanName);
DefaultListableBeanFactory->DefaultBeanDefinitionDocumentReader: return 
DefaultBeanDefinitionDocumentReader->AbstractApplicationContext: obtainFreshBeanFactory() is over,return DefaultListableBeanFactory
  • существуетparsePropertyElements(ele, bd);Когда значение атрибута класса помещается в bean-компонент и возвращается BeanDefinitionHolder.
  • существуетthis.beanDefinitionNames.add(beanName);иthis.beanDefinitionMap.put(beanName, beanDefinition);Когда первый должен поместить beanName в очередь, последний должен поместить BeanDefinition в карту, и на этом регистрация завершена. При более позднем создании экземпляра BeanDefinition в beanDefinitionMap извлекается и создается один за другим.

заключить:

  1. ApplicationContext делегирует работу по синтаксическому анализу файла конфигурации BeanDefinitionReader, а затем BeanDefinitionReader считывает файл конфигурации как документ xml, а затем делегирует его BeanDefinitionDocumentReader.
  2. Компонент BeanDefinitionDocumentReader действует как маршрут на основе пространства имен и имени элемента элемента xml.Фактическая работа по синтаксическому анализу делегируется для завершения BeanDefinitionParserDelegate.
  3. После завершения синтаксического анализа BeanDefinitionParserDelegate он вернет BeanDefinitionHolder в BeanDefinitionDocumentReader, где он будет делегирован в DefaultListableBeanFactory для завершения регистрации компонента.
  4. XmlBeanDefinitionReader (подсчет, разбор XML-документов), BeanDefinitionDocumentReader (использование XML-документов, разбор и регистрация), BeanDefinitionParserDelegate (фактическая работа по разбору). Видно, что в процессе парсинга бинов разделение труда между этими тремя компонентами относительно четкое, и каждый выполняет свои обязанности.

метод getBean

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        JSONArray person = (JSONArray) context.getBean("aaa");

Рекомендуемый блог

Пополнить

[Изучение исходного кода Spring] getBean (включено)один изBeanDefinitionParseDelegate #parseBeanDefinitionAttributesметод, место выполнения этого метода, когда пользовательский синтаксический анализ xml читается выше, запустите, чтобыBeanDefinitionParserDelegate #parseBeanDefinitionElementметод, как показано ниже

блок-схема

Полная интерпретация исходного кода GetBeanЭта статья более хаотична, я трачу время на то, чтобы перерисовать следующий график, и в статье больше шансов понять:

Дополнение к тексту временной диаграммы:

SpringMain-> AbstractBeanFactory: getBean
AbstractBeanFactory-> AbstractBeanFactory#doGetBean: doGetBean
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingleton(beanName)
AbstractBeanFactory#doGetBean-> AbstractBeanFactory#getObjectForBeanInstance: getObjectForBeanInstance
AbstractBeanFactory#doGetBean-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedLocalBeanDefinition
AbstractBeanFactory#getMergedLocalBeanDefinition-> AbstractBeanFactory#getMergedLocalBeanDefinition: getMergedBeanDefinition
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: registerDependentBean
AbstractBeanFactory#doGetBean-> DefaultSingletonBeanRegistry: getSingleton
DefaultSingletonBeanRegistry-> DefaultSingletonBeanRegistry: beforeSingletonCreation
AbstractBeanFactory#doGetBean-> AbstractAutowireCapableBeanFactory#createBean: createBean
AbstractAutowireCapableBeanFactory#createBean-> AbstractAutowireCapableBeanFactory#doCreateBean: doCreateBean
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#createBeanInstance: createBeanInstance
AbstractAutowireCapableBeanFactory#createBeanInstance-> AbstractAutowireCapableBeanFactory#instantiateBean: instantiateBean
AbstractAutowireCapableBeanFactory#instantiateBean->SimpleInstantiationStrategy: instantiate
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors: applyMergedBeanDefinitionPostProcessors
AbstractAutowireCapableBeanFactory#applyMergedBeanDefinitionPostProcessors-> AutowiredAnnotationBeanPostProcessor: postProcessMergedBeanDefinition
AutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: findAutowiringMetadata
AutowiredAnnotationBeanPostProcessor-> AutowiredAnnotationBeanPostProcessor: buildAutowiringMetadata
AbstractAutowireCapableBeanFactory#doCreateBean-> AbstractAutowireCapableBeanFactory#populateBean: populateBean
AbstractAutowireCapableBeanFactory#populateBean-> AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues: postProcessPropertyValues
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> InjectionMetadata: inject.
note right of InjectionMetadata: @Resource
AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues-> AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: inject
note right of AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement: @Autowired&@Value
AbstractAutowireCapableBeanFactory#populateBean-> AbstractAutowireCapableBeanFactory#populateBean: applyPropertyValues

существуетAutowiredAnnotationBeanPostProcessor#buildAutowiringMetadataВ этом методе Spring создаст разные классы для сохранения и возврата в соответствии с различными аннотациями, такими как @Resource или @AutoWired. Различные классы, созданные здесь, будут вInjectionMetadata #injectКогда он сработает, он вызовет методы внедрения разных классов для внедрения свойств.

круговая зависимость

Рекомендуемый блог

Суммировать

Кэш третьего уровня

/** Cache of singleton objects: bean name --> bean instance */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(256);

/** Cache of singleton factories: bean name --> ObjectFactory */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<String, ObjectFactory<?>>(16);

/** Cache of early singleton objects: bean name --> bean instance */
private final Map<String, Object> earlySingletonObjects = new HashMap<String, Object>(16);
тайник использовать
singletonObjects Используется для хранения полностью инициализированных bean-компонентов, bean-компоненты, взятые из этого кеша, могут использоваться напрямую.
earlySingletonObjects Содержит исходный объект компонента (свойства еще не заполнены), используемый для разрешения циклических зависимостей.
singletonFactories Храните объекты bean factory для разрешения циклических зависимостей

Вот три таких примера. A зависит от B (B не зависит от A)

Кэш L1 A зависит от B && B зависит от A

Кэш L3 A зависит от B && B зависит от A + B зависит от C && C зависит от A

Категории