Подробное объяснение автоматической настройки Spring Boot 3.x.
Подробное объяснение автоматической настройки Spring Boot 3.x.

Spring Boot :3.1 Java: 17

Предисловие

Spring Boot 3.x серединаизавтоматический КонфигурацияиспользоватьMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ,инетMETA-INF/spring.factories,Это изменение на самом деле2.7извремена изменились

Введение в документ версии 2.6.9

Знакомство с версией 2.7.0

В документе середина есть подробное введение в Create Yourself из Starteriz.,《Spring Boot Справочное руководство на китайском языке: создайте собственную автоматическую конфигурацию》

Принцип загрузки

Spring Boot 3.xизавтоматический Конфигурация Запись о загрузкеMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports ,Spring Boot прочитает класс автоматической конфигурации в этом файле и создаст его экземпляр. Мы используем этот файл в качестве точки входа.

если вы новичок,и Нет Доступная информация,Можно использовать функцию глобального поиска файлов IDE.,Ключевые слова для поиска,Если я ищуorg.springframework.boot.autoconfigure.AutoConfiguration.imports Результат получается следующий, и тогда точку входа для загрузки файла можно определить по точкам останова.

Это может быть известно,файлиз Загрузка осуществляется с помощьюAutoConfigurationImportSelectorдобрыйруководитьиметь дело с,ноAutoConfigurationImportSelectorдобрый Как загрузить зановоиз。

Через стек точек останова мы видим, что для загрузки используется Spring. рамкаrefresh()серединаизinvokeBeanFactoryPostProcessors,Его функция — создавать экземплярыBeanперед загрузкой доп.определениеизBeanв контекстсередина,Давайте разберемся с самого начала,Сильная способностьиз Можетвладелецметод Прочтите самостоятельно。

информация стека

AbstractApplicationContext-invokeBeanFactoryPostProcessors

Язык кода:javascript
копировать
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Если beanFactory содержит LoadTimeWeaver, используйте временный ClassLoader для обработки. LoadTimeWeaver — это технология динамического объединения для загрузчиков классов.
		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

Методиз Функция:Создать экземпляр и позвонитьзарегистрироватьсяизBeanFactoryPostProcessor

getBeanFactoryPostProcessors() используется дляполучатьвсеизBeanFactoryPostProcessorПример,BeanFactoryPostProcessorЭкземпляр пройденApplicationContextInitializerПриходитьнагрузкав контекстсередина,ApplicationContextInitializerиз Принцип загрузки Можетпроходить Переднийиз Понимание статьи«Подробное объяснение инициализатора системы Spring Boot»

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); Делегируйте обработку BeanFactoryPostProcessor.

PostProcessorRegistrationDelegate-invokeBeanFactoryPostProcessors

Язык кода:javascript
копировать
public static void invokeBeanFactoryPostProcessors(
			ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

		Set<String> processedBeans = new HashSet<>();
		//Если beanFactory Является ли реализация BeanDefinitionRegistry, первый процесс BeanDefinitionRegistryPostProcessors
		if (beanFactory instanceof BeanDefinitionRegistry registry) {
			List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
			List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

			for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
				if (postProcessor instanceof BeanDefinitionRegistryPostProcessor registryProcessor) {
					registryProcessor.postProcessBeanDefinitionRegistry(registry);
					registryProcessors.add(registryProcessor);
				}
				else {
					regularPostProcessors.add(postProcessor);
				}
			}

			List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

			// Сначала обработайте PriorityOrdered из BeanDefinitionRegistryPostProcessor
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			
//Обработка BeanDefinitionRegistryPostProcessors
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			// перерабатывать Ordered из BeanDefinitionRegistryPostProcessor
			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}
			sortPostProcessors(currentRegistryProcessors, beanFactory);
			registryProcessors.addAll(currentRegistryProcessors);
			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
			currentRegistryProcessors.clear();

			 // наконециметь дело с оставшимся из BeanDefinitionRegistryPostProcessor,до Нетновыйиз BeanDefinitionRegistryPostProcessor пока не добавлено
			boolean reiterate = true;
			while (reiterate) {
				reiterate = false;
				postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
				for (String ppName : postProcessorNames) {
					if (!processedBeans.contains(ppName)) {
						currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
						processedBeans.add(ppName);
						reiterate = true;
					}
				}
				sortPostProcessors(currentRegistryProcessors, beanFactory);
				registryProcessors.addAll(currentRegistryProcessors);
				invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
				currentRegistryProcessors.clear();
			}

			// Обработать все BeanFactoryPostProcessor
			invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
			invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
		}

		else {
			// иметь дело собычноизконтекстсерединаизBeanFactoryPostProcessor
	invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
		}

		//получатьвсерутинизацияBean,но не инициализирован,Зарезервировать на более поздний этапизpost-processorsиметь дело с
		String[] postProcessorNames =
				beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

		
		//Отдельно реализуем PriorityOrdered, Ordered и другие изBeanFactoryPostProcessors
		List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (processedBeans.contains(ppName)) {
				// пропустить уже есть дело сиз
			}
			else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		
		//голова Сначала обработайте реализацию PriorityOrderedизBeanFactoryPostProcessors
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

		//иметь дело реализует OrderedизBeanFactoryPostProcessors
		List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
		for (String postProcessorName : orderedPostProcessorNames) {
			orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);

		// наконециметь дело сOtherизBeanFactoryPostProcessors
		List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
		for (String postProcessorName : nonOrderedPostProcessorNames) {
			nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
		}
		invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

		// очистить кеш
		beanFactory.clearMetadataCache();
	}

invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); Это ключевой момент при автоматической настройке.

PostProcessorRegistrationDelegate-invokeBeanDefinitionRegistryPostProcessors

Язык кода:javascript
копировать
private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {

//Цикл обработки Реализация BeanDefinitionRegistryPostProcessor
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
	//Регистрация шагов
		StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
				.tag("postProcessor", postProcessor::toString);
		postProcessor.postProcessBeanDefinitionRegistry(registry);
		postProcessBeanDefRegistry.end();
	}
}

BeanDefinitionRegistryPostProcessorинтерфейсунаследованныйBeanFactoryPostProcessorинтерфейс,разрешено во время инициализацииBeanПример Изменено ранее、добавить в、удалитьконтейнерсерединазарегистрироватьсяизBeanопределениеинформация

существовать Должен ПримеризSpringBoot-Demoсередина,Существует только одна реализация BeanDefinitionRegistryPostProcessor.,Прямо сейчасConfigurationClassPostProcessor

ConfigurationClassPostProcessor-postProcessBeanDefinitionRegistry

Язык кода:javascript
копировать
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
//Рассчитываем хеш-код
		int registryId = System.identityHashCode(registry);
		//Определяем, было ли оно обработано
		if (this.registriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
		}
		if (this.factoriesPostProcessed.contains(registryId)) {
			throw new IllegalStateException(
					"postProcessBeanFactory already called on this post-processor against " + registry);
		}
		this.registriesPostProcessed.add(registryId);

//Конфигурация процесса Информация об определении компонента
		processConfigBeanDefinitions(registry);
	}

ConfigurationClassPostProcessor-processConfigBeanDefinitions

Язык кода:javascript
копировать
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		//получатьконтейнерсерединавсеизbeanопределениеимя
		String[] candidateNames = registry.getBeanDefinitionNames();

		for (String beanName : candidateNames) {
		// получать bean изопределение
			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
			// Проверьте это bean Было ли оно обработано в категорию Конфигурация
			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {
				if (logger.isDebugEnabled()) {
					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
				}
			}
			// Проверьте это bean Вы кандидат в категорию Конфигурация?
			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
			}
		}

		// если Нетнуждатьсяиметь дело сиз Конфигурациядобрый,затем вернитесь напрямую
		if (configCandidates.isEmpty()) {
			return;
		}

		// верно Конфигурациядобрыйкандидат ВОЗруководитьсортировать,Как определено ранее @Order Сортировка значений
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// Проверьте, есть ли самодельные bean Стратегия генерации имени
		SingletonBeanRegistry sbr = null;
		if (registry instanceof SingletonBeanRegistry _sbr) {
			sbr = _sbr;
			if (!this.localBeanNameGeneratorSet) {
				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
				if (generator != null) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// Разобрать каждый @Configuration добрый
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
			//анализ
			parser.parse(candidates);
			//проверять
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			//Удалить уже разобранный издобрый
			configClasses.removeAll(alreadyParsed);

			// Read the model and create bean definitions based on its content
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);
			processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
// исследоватьновыйиз BeanDefinition да Не включаетновыйиз Конфигурациядобрыйкандидат ВОЗ
			candidates.clear();
			if (registry.getBeanDefinitionCount() > candidateNames.length) {
				String[] newCandidateNames = registry.getBeanDefinitionNames();
				Set<String> oldCandidateNames = Set.of(candidateNames);
				Set<String> alreadyParsedClasses = new HashSet<>();
				for (ConfigurationClass configurationClass : alreadyParsed) {
					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
				}
				for (String candidateName : newCandidateNames) {
					if (!oldCandidateNames.contains(candidateName)) {
						BeanDefinition bd = registry.getBeanDefinition(candidateName);
						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
								!alreadyParsedClasses.contains(bd.getBeanClassName())) {
							candidates.add(new BeanDefinitionHolder(bd, candidateName));
						}
					}
				}
				candidateNames = newCandidateNames;
			}
		}
		while (!candidates.isEmpty());

		// зарегистрироваться ImportRegistry за одного боб для поддержки @ImportAware ConfigurationClass
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}

		// хранилище PropertySourceDescriptors для удобного использования в AOT
		this.propertySourceDescriptors = parser.getPropertySourceDescriptors();

		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory cachingMetadataReaderFactory) {
			// очистить кеш,Предотвратить невозможность обновления из-за кэшановыйпривести кизпроблема с ошибкой
			cachingMetadataReaderFactory.clearCache();
		}
	}

Код здесь очень длинный,верно ВКонфигурациядобрыйизанализировать,существоватьparser.parse(candidates)середина Заканчивать。

parserпеременнаяиз Примердля:ConfigurationClassParser

ConfigurationClassParser-parse

Язык кода:javascript
копировать
public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
			// если BeanDefinition это AnnotatedBeanDefinition, вам необходимо проанализировать BeanDefinition серединаизаннотацияинформация
				if (bd instanceof AnnotatedBeanDefinition annotatedBeanDef) {
					parse(annotatedBeanDef.getMetadata(), holder.getBeanName());
				}
				// если BeanDefinition нет AnnotatedBeanDefinition и имеет beanClass атрибут, затем проанализируйте beanClass серединаизаннотацияинформация
				else if (bd instanceof AbstractBeanDefinition abstractBeanDef && abstractBeanDef.hasBeanClass()) {
					parse(abstractBeanDef.getBeanClass(), holder.getBeanName());
				}
				else {
				// если BeanDefinition Нет beanClass атрибут, затем проанализируйте BeanDefinition серединаиз beanClassName указанныйиздобрыйсерединаизаннотацияинформация
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}
		
		//Обработать всеизDeferredImportSelectorПример
		this.deferredImportSelectorHandler.process();
	}

существоватьначинатьизкогда,Мы уже знаем настоящуюанализироватьавтоматический КонфигурациядобрыйдаAutoConfigurationImportSelector,AutoConfigurationImportSelector ОсуществленныйDeferredImportSelectorинтерфейс,и Здесь случайно есть одинdeferredImportSelectorHandlerПриходить Обработать всеизdeferredImportSelectorHandlerПример。ВзглянитеDeferredImportSelectorHandlerсерединаизprocess。

DeferredImportSelectorHandler-process

Язык кода:javascript
копировать
public void process() {
			List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors;
			this.deferredImportSelectors = null;
			try {
				if (deferredImports != null) {
					DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
					deferredImports.sort(DEFERRED_IMPORT_COMPARATOR);
					deferredImports.forEach(handler::register);
					handler.processGroupImports();
				}
			}
			finally {
				this.deferredImportSelectors = new ArrayList<>();
			}
		}

DeferredImportSelectorGroupingHandler класс в Spring Boot средняя обработка DeferredImportSelector Вспомогательный класс интерфейса в основном используется для группировки DeferredImportSelector по группе для обработки.

Здесь мы хотим сосредоточиться наhandler.processGroupImports(),позвонить вDeferredImportSelectorGroupingHandlerдобрыйизprocessGroupImportsметод。

DeferredImportSelectorGroupingHandler-processGroupImports

Язык кода:javascript
копировать
public void processGroupImports() {
			//Перебираем все группы
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				//получаем фильтр кандидатов
				Predicate<String> exclusionFilter = grouping.getCandidateFilter();
				//Обходим каждый элемент группы серединаиз
				grouping.getImports().forEach(entry -> {
					ConfigurationClass configurationClass = this.configurationClasses.get(entry.getMetadata());
					try {
					//Обрабатываем текущий элемент
						processImports(configurationClass, asSourceClass(configurationClass, exclusionFilter),
								Collections.singleton(asSourceClass(entry.getImportClassName(), exclusionFilter)),
								exclusionFilter, false);
					}
					catch (BeanDefinitionStoreException ex) {
						throw ex;
					}
					catch (Throwable ex) {
						throw new BeanDefinitionStoreException(
								"Failed to process import candidates for configuration class [" +
										configurationClass.getMetadata().getClassName() + "]", ex);
					}
				});
			}
		}

Здесь первое, что нужно сделать, это сосредоточиться наgrouping.getImports(),существоватьздесьверноавтоматический Конфигурациядобрыйруководить Понятнонагрузка

DeferredImportSelectorGrouping-getImports

Язык кода:javascript
копировать
public Iterable<Group.Entry> getImports() {
	for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
//иметь дело с Каждая группа изDeferredImportSelectorHolder
		this.group.process(deferredImport.getConfigurationClass().getMetadata(),
				deferredImport.getImportSelector());
	}
	//возвращатьсянуждатьсяимпортироватьиздобрый
	return this.group.selectImports();
}

this.group.processсерединавойти вAutoConfigurationImportSelectorизвнутреннийдобрыйAutoConfigurationGroupсередина

AutoConfigurationImportSelector-AutoConfigurationGroup-process

Язык кода:javascript
копировать
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
			() -> String.format("Only %s implementations are supported, got %s",
					AutoConfigurationImportSelector.class.getSimpleName(),
					deferredImportSelector.getClass().getName()));
					
					//Преобразовать в AutoConfigurationImportSelector,получатьAutoConfigurationEntry
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
		.getAutoConfigurationEntry(annotationMetadata);
	
//Добавить в переменную autoConfigurationEntries для дальнейшего использования
this.autoConfigurationEntries.add(autoConfigurationEntry);
//настраиватьentriesпеременная,импортироватьиздобрый Навамотоаннотация Отображение отношений
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}

Здесь после принудительного преобразования deferredImportSelector в AutoConfigurationImportSelector метод getAutoConfigurationEntry вызывается снова.

AutoConfigurationImportSelector-getAutoConfigurationEntry

Язык кода:javascript
копировать
protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    // еслиавтоматический Конфигурация Нет в наличии,затем вернись EMPTY_ENTRY
	if (!isEnabled(annotationMetadata)) {
		return EMPTY_ENTRY;
	}
	// получатьаннотацияизсвойство
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
	// получатькандидатавтоматический Конфигурациядобрый,Ключ к этой статье
	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
	// Удалить дубликатыизавтоматический Конфигурациядобрый
	configurations = removeDuplicates(configurations);
	// получатьнуждатьсяисключатьизавтоматический Конфигурациядобрый,spring.autoconfigure.excludeКонфигурация
	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
	// исследоватьда Есть ли какой-нибудьодеялоисключатьизавтоматический Конфигурациядобрый
	checkExcludedClasses(configurations, exclusions);
	// Удалитьисключенноеизавтоматический Конфигурациядобрый
	configurations.removeAll(exclusions);
	// использовать ConfigurationClassFilter фильтравтоматический Конфигурациядобрый
	configurations = getConfigurationClassFilter().filter(configurations);
	// Отправлять события автоматической настройки
	fireAutoConfigurationImportEvents(configurations, exclusions);
	return new AutoConfigurationEntry(configurations, exclusions);
}

Методиз Функция Согласно данномуизаннотацияметаданныеполучатьавтоматический Конфигурацияэлемент,верно Вавтоматический Конфигурацияизнагрузка,ключсуществоватьgetCandidateConfigurations(annotationMetadata, attributes)

AutoConfigurationImportSelector-getCandidateConfigurations

Язык кода:javascript
копировать
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
//Загружаем полное имя AutoConfiguration из доброго пути изMETA-INF/springсередина
	List<String> configurations = ImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())
		.getCandidates();
	Assert.notEmpty(configurations,
			"No auto configuration classes found in "
					+ "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports. If you "
					+ "are using a custom packaging, make sure that file is correct.");
	return configurations;
}

МетодизImportCandidates.load(AutoConfiguration.class, getBeanClassLoader())Соберу это воединоMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.importsпуть,用ВнагрузкаопределениеизAutoConfigurationдобрый。

ImportCandidates-ImportCandidates

Язык кода:javascript
копировать
public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {
	Assert.notNull(annotation, "'annotation' must not be null");
	ClassLoader classLoaderToUse = decideClassloader(classLoader);
	//ВоляMETA-INF/spring/%s.importsСтрока отформатирована, как указаноизпуть
	String location = String.format(LOCATION, annotation.getName());
	Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);
	List<String> importCandidates = new ArrayList<>();
	while (urls.hasMoreElements()) {
		URL url = urls.nextElement();
		importCandidates.addAll(readCandidateConfigurations(url));
	}
	return new ImportCandidates(importCandidates);
}

существоватьgrouping.getImports()получатьприезжатьвсехотетьимпортироватьизAutoConfigurationEntryназад,проходитьprocessImportsруководитьиметь дело с

ConfigurationClassParser-processImports

Язык кода:javascript
копировать
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
        Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
        boolean checkForCircularImports) {

    // если Нет Можетимпортироватьиздобрый,затем вернитесь напрямую
    if (importCandidates.isEmpty()) {
        return;
    }

    // Проверьте циклический импорт
    if (checkForCircularImports && isChainedImportOnStack(configClass)) {
        this.problemReporter.error(new CircularImportProblem(configClass, this.importStack));
    }
    else {
        // Волятекущий Конфигурациядобрыйвтолкнутьимпортироватькучасередина
        this.importStack.push(configClass);
        try {
            // иметь дело скаждыйимпортироватьиздобрый
            for (SourceClass candidate : importCandidates) {
                if (candidate.isAssignable(ImportSelector.class)) {
                    // Candidate class is an ImportSelector -> delegate to it to determine imports
                    // есликандидатдобрыйда ImportSelector изребенокдобрый,тогда оставь это себе Приходить Решатьимпортировать Которыйдобрый
                    Class<?> candidateClass = candidate.loadClass();
                    ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
                            this.environment, this.resourceLoader, this.registry);
                    Predicate<String> selectorFilter = selector.getExclusionFilter();
                    if (selectorFilter != null) {
                        exclusionFilter = exclusionFilter.or(selectorFilter);
                    }
                    if (selector instanceof DeferredImportSelector deferredImportSelector) {
                        this.deferredImportSelectorHandler.handle(configClass, deferredImportSelector);
                    }
                    else {
                        String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
                        Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
                        processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
                    }
                }
                else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
                    // Candidate class is an ImportBeanDefinitionRegistrar ->
                    // delegate to it to register additional bean definitions
                    // есликандидатдобрыйда ImportBeanDefinitionRegistrar изребенокдобрый,тогда оставь это себе Приходитьзарегистрироваться Болееиз Bean определение
                    Class<?> candidateClass = candidate.loadClass();
                    ImportBeanDefinitionRegistrar registrar =
                            ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
                                    this.environment, this.resourceLoader, this.registry);
                    configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
                }
                else {
                    // Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
                    // process it as an @Configuration class
                    // есликандидатдобрыйнет ImportSelector или ImportBeanDefinitionRegistrar изребенокдобрый,но Воля其作для @Configuration добрый Приходитьиметь дело с
                    this.importStack.registerImport(
                            currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
                    processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
                }
            }
        }
        catch (BeanDefinitionStoreException ex) {
            throw ex;
        }
        catch (Throwable ex) {
            throw new BeanDefinitionStoreException(
                    "Failed to process import candidates for configuration class [" +
                    configClass.getMetadata().getClassName() + "]: " + ex.getMessage(), ex);
        }
        finally {
            this.importStack.pop();
        }
    }
}

кMybatisPlusLanguageDriverAutoConfigurationавтоматический Конфигурация Например,встречапроходитьprocessConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);руководитьиметь дело с。

ConfigurationClassParser-processConfigurationClass

Язык кода:javascript
копировать
protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
    // если Должен Конфигурациядобрыйпомечено как пропущенное,затем вернитесь напрямую,Нетнуждатьсяперерабатывать
	if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
		return;
	}

    // если Уже сохраненосуществовать То же имяиз Конфигурациядобрый,тогда суди обоихизимпортироватьситуация и слияние
	ConfigurationClass existingClass = this.configurationClasses.get(configClass);
	if (existingClass != null) {
		if (configClass.isImported()) {
			if (existingClass.isImported()) {
				existingClass.mergeImportedBy(configClass);
			}
			// Otherwise ignore new imported config class; existing non-imported class overrides it.
			return;
		}
		else {
			// Explicit bean definition found, probably replacing an import.
			// Let's remove the old one and go with the new one.
			this.configurationClasses.remove(configClass);
			this.knownSuperclasses.values().removeIf(configClass::equals);
		}
	}

    // рекурсивно дело с Должен Конфигурациядобрыйи его отецдобрыйизотношения наследства,анализировать Bean определение
	SourceClass sourceClass = asSourceClass(configClass, filter);
	do {
		sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
	}
	while (sourceClass != null);

    // Воля Должен Конфигурациядобрыйприсоединиться к configurationClasses середина
	this.configurationClasses.put(configClass, configClass);
}

ConfigurationClassParser-doProcessConfigurationClass

Язык кода:javascript
копировать
protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// если Должен Конфигурациядобрыйодеяло@Componentаннотацияотметка,затем рекурсияиметь дело с Любое вложение доброе.
			processMemberClasses(configClass, sourceClass, filter);
		}

		// иметь дело с @PropertySource
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.propertySourceRegistry != null) {
				this.propertySourceRegistry.processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// иметь дело с@ComponentScanаннотация
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Проверить сканированиеизопределениенаборда Есть ли какой-нибудь任何进一步из Конфигурациядобрый,исуществоватьнуждатьсярекурсия временианализировать

				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// иметь дело с@Import
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// иметь дело с@ImportResource
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArray("locations");
			Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");
			for (String resource : resources) {
				String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);
				configClass.addImportedResource(resolvedResource, readerClass);
			}
		}

		// иметь дело содинокийиз@Beanметод
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// иметь дело синтерфейсначальствоизпо умолчаниюметод
		processInterfaces(configClass, sourceClass);

		// иметь дело сдогонятьдобрый
		if (sourceClass.getMetadata().hasSuperClass()) {
			String superclass = sourceClass.getMetadata().getSuperClassName();
			if (superclass != null && !superclass.startsWith("java") &&
					!this.knownSuperclasses.containsKey(superclass)) {
				this.knownSuperclasses.put(superclass, configClass);
				// 找приезжатьдогонятьдобрый,возвращаться其注释метаданныеи递归
				return sourceClass.getSuperClass();
			}
		}

		// Нетдогонятьдобрый,Заканчивать
вернуть ноль;
}

Подвести итог

На рисунке показан весь процесс автоматической загрузки и анализа конфигурации.

boy illustration
【Java】Решено: org.springframework.web.HttpRequestMethodNotSupportedException
boy illustration
Native js отправляет запрос на публикацию_javascript отправляет запрос на публикацию
boy illustration
.net PDF в Word_pdf в Word
boy illustration
[Пул потоков] Как Springboot использует пул потоков
boy illustration
Подробное объяснение в одной статье: Как работают пулы потоков
boy illustration
Серия SpringCloud (6) | Поговорим о балансировке нагрузки
boy illustration
IDEA Maven может упаковать все импортное полностью красное решение — универсальное решение.
boy illustration
Последний выпуск 2023 года, самое полное руководство по обучению Spring Boot во всей сети (с интеллект-картой).
boy illustration
[Решено — Практическая работа] SaTokenException: запрос не может быть получен в контексте, отличном от Интернета. Решение проблем — Практическая работа.
boy illustration
HikariPool-1 - Connection is not available, request timed out after 30000ms
boy illustration
Power Query: автоматическое суммирование ежемесячных данных с обновлением одним щелчком мыши.
boy illustration
установка Ubuntu в среде npm
boy illustration
3 Бесплатные системы управления складом (WMS) .NET с открытым исходным кодом
boy illustration
Глубокое погружение в библиотеку Python Lassie: мощный инструмент для автоматизации извлечения метаданных
boy illustration
Объяснение прослушивателя серии Activiti7 последней версии 2023 года
boy illustration
API-интерфейс Jitu Express для электронных счетов-Express Bird [просто для понимания]
boy illustration
Каковы архитектуры микросервисов Java. Серверная часть плавающей области обслуживания
boy illustration
Описание трех режимов жизненного цикла службы внедрения зависимостей Asp.net Core.
boy illustration
Java реализует пользовательские аннотации для доступа к интерфейсу без проверки токена.
boy illustration
Серверная часть Unity добавляет поддержку .net 8. Я еще думал об этом два дня назад, и это сбылось.
boy illustration
Проект с открытым исходным кодом | Самый элегантный метод подписки на публичные аккаунты WeChat на данный момент
boy illustration
Разрешения роли пользователя Gitlab Гость, Репортер, Разработчик, Мастер, Владелец
boy illustration
Spring Security 6.x подробно объясняет механизм управления аутентификацией сеанса в этой статье.
boy illustration
[Основные знания ASP.NET] — Аутентификация и авторизация — Использование удостоверений для аутентификации.
boy illustration
Соединение JDBC с базой данных MySQL в jsp [легко понять]
boy illustration
[Уровень няни] Полный процесс развертывания проекта Python (веб-страницы Flask) в Docker.
boy illustration
6 способов чтения файлов свойств, рекомендуем собрать!
boy illustration
Графическое объяснение этапа строительства проекта IDEA 2021 Spring Cloud (базовая версия)
boy illustration
Подробное объяснение технологии междоменного запроса данных JSONP.
boy illustration
Учебное пособие по SpringBoot (14) | SpringBoot интегрирует Redis (наиболее полный во всей сети)