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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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();
}
}
// Нетдогонятьдобрый,Заканчивать
вернуть ноль;
}
На рисунке показан весь процесс автоматической загрузки и анализа конфигурации.