SpringBoot学习笔记(三) 自动装配原理

SpringBoot学习笔记(二) 整合redis+mybatis+Dubbo,本篇文章我们开始分析SpringBoot的自动装配原理。

概述

前面已经介绍了Spring的加载过程,经历扫描配置文件--收集beanName--实例化bean这几步,SpringBoot同样如此,源于Spring,高于Spring,省去了”简单模式(特殊场景如多数据源引入,需要额外的单独配置)下xml配置文件的繁琐过程。下面让我们来揭秘SpringBoot的自动装配原理。

源码解读

1.先从run方法进入,

public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

2.进入到run方法中

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
    }

3.最后点到这里

4.继续深入

private void refreshContext(ConfigurableApplicationContext context) {
        this.refresh((ApplicationContext)context);
        if (this.registerShutdownHook) {
            try {
                context.registerShutdownHook();
            } catch (AccessControlException var3) {
                ;
            }
        }

    }

5.进入到refresh

protected void refresh(ConfigurableApplicationContext applicationContext) {
        applicationContext.refresh();
    }

6.继续进入方法

org.springframework.context.support.AbstractApplicationContext#refresh

public void refresh() throws BeansException, IllegalStateException {
        Object var1 = this.startupShutdownMonitor;
        synchronized(this.startupShutdownMonitor) {
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                this.invokeBeanFactoryPostProcessors(beanFactory);  //看这里
                this.registerBeanPostProcessors(beanFactory);
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var9) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
                }

                this.destroyBeans();
                this.cancelRefresh(var9);
                throw var9;
            } finally {
                this.resetCommonCaches();
            }

        }
    }

7.进入到invokeBeanFactoryPostProcessors方法内部

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
        //这里
       PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, this.getBeanFactoryPostProcessors());
        if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean("loadTimeWeaver")) {
            beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
            beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
        }
    }
public static void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

     sortPostProcessors(currentRegistryProcessors, beanFactory);
            registryProcessors.addAll(currentRegistryProcessors);
            // 这里
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            currentRegistryProcessors.clear();
}

8.继续进入

private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
        Iterator var2 = postProcessors.iterator();

        while(var2.hasNext()) {
            BeanDefinitionRegistryPostProcessor postProcessor = (BeanDefinitionRegistryPostProcessor)var2.next();
            postProcessor.postProcessBeanDefinitionRegistry(registry);
        }

    }

9.进入到postProcessor.postProcessBeanDefinitionRegistry(registry)方法

10.看这里

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);
        } else if (this.factoriesPostProcessed.contains(registryId)) {
            throw new IllegalStateException("postProcessBeanFactory already called on this post-processor against " + registry);
        } else {
            this.registriesPostProcessed.add(registryId);
            this.processConfigBeanDefinitions(registry);
        }
    }

11.看最后一句this.processConfigBeanDefinitions(registry) 进入该方法

调试程序发现

这里有我们熟悉的RedisTemplateAutoConfiguration类

并且在上一步中

就已经读读出了配置类。

这里注意:

configClasses获取的是starts中依赖的组件,用rabbitmq举例,组件中如果不对其进行引用那么config中是没有相关类信息的,相反,如果对rabbitmq进行引用则可以加载。

 

============以下是分析如何从spring.factories中加载XXXAutoConfigration的过程============

12.继续,configClasses的具体读取应该是在parser.parse(candidates)

进入方法中

public void parse(Set<BeanDefinitionHolder> configCandidates) {
        Iterator var2 = configCandidates.iterator();

        while(var2.hasNext()) {
            BeanDefinitionHolder holder = (BeanDefinitionHolder)var2.next();
            BeanDefinition bd = holder.getBeanDefinition();

            try {
                if (bd instanceof AnnotatedBeanDefinition) {
                    this.parse(((AnnotatedBeanDefinition)bd).getMetadata(), holder.getBeanName());
                } else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition)bd).hasBeanClass()) {
                    this.parse(((AbstractBeanDefinition)bd).getBeanClass(), holder.getBeanName());
                } else {
                    this.parse(bd.getBeanClassName(), holder.getBeanName());
                }
            } catch (BeanDefinitionStoreException var6) {
                throw var6;
            } catch (Throwable var7) {
                throw new BeanDefinitionStoreException("Failed to parse configuration class [" + bd.getBeanClassName() + "]", var7);
            }
        }

        this.deferredImportSelectorHandler.process();
    }

13.随便点到一个this.parse方法中

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
        if (!this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
            ConfigurationClass existingClass = (ConfigurationClass)this.configurationClasses.get(configClass);
            if (existingClass != null) {
                if (configClass.isImported()) {
                    if (existingClass.isImported()) {
                        existingClass.mergeImportedBy(configClass);
                    }

                    return;
                }

                this.configurationClasses.remove(configClass);
                this.knownSuperclasses.values().removeIf(configClass::equals);
            }

            ConfigurationClassParser.SourceClass sourceClass = this.asSourceClass(configClass, filter);

            do {
                // 点这里
                sourceClass = this.doProcessConfigurationClass(configClass, sourceClass, filter);
            } while(sourceClass != null);

            this.configurationClasses.put(configClass, configClass);
        }
    }

 14.this.doProcessConfigurationClass(configClass, sourceClass, filter);

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
      		// 在这递归的,会回到上一步代码中
			processMemberClasses(configClass, sourceClass, filter);
		}


		// Process any @Import annotations
  		// 看这个名字可以知道这个方法的作用
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
	}

getImports(sourceClass)方法是一个递归调用,用来收集Import注解。

15.继续看processImports方法

org.springframework.context.annotation.ConfigurationClassParser#processImports

private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
			Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
			boolean checkForCircularImports) {
		...
		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
						Class<?> candidateClass = candidate.loadClass();
						ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
								this.environment, this.resourceLoader, this.registry);
						Predicate<String> selectorFilter = selector.getExclusionFilter();

						if (selector instanceof DeferredImportSelector) {
              				// 因为AutoConfigurationImportSelector继承了DeferredImportSelector,所以会进入这个方法,放到
              				// 列表里处理,直接放到一个List中。
							this.deferredImportSelectorHandler.handle(configClass, (DeferredImportSelector) selector);
						}
					}
        }
        ...
			}
		}
	}

16.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorHandler#handle

public void handle(ConfigurationClass configClass, DeferredImportSelector importSelector) {
			DeferredImportSelectorHolder holder = new DeferredImportSelectorHolder(configClass, importSelector);
			if (this.deferredImportSelectors == null) {
				DeferredImportSelectorGroupingHandler handler = new DeferredImportSelectorGroupingHandler();
				handler.register(holder);
				handler.processGroupImports();
			}
			else {
				this.deferredImportSelectors.add(holder);
			}
		}

17.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#register代码

public void register(DeferredImportSelectorHolder deferredImport) {
      // AutoConfigurationImportSelector返回的是AutoConfigurationGroup.class,代码中已写死
			Class<? extends Group> group = deferredImport.getImportSelector().getImportGroup();
      // 封装成 DeferredImportSelector.Group 对象,并放到了groupings中,groupings是LinkedHashMap
      // Group对象是用AutoConfigurationGroup.class生成
			DeferredImportSelectorGrouping grouping = this.groupings.computeIfAbsent(
					(group != null ? group : deferredImport),
					key -> new DeferredImportSelectorGrouping(createGroup(group)));
			grouping.add(deferredImport);
			this.configurationClasses.put(deferredImport.getConfigurationClass().getMetadata(),
					deferredImport.getConfigurationClass());
		}

18.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGroupingHandler#processGroupImports方法,SpringSPI的调用点=

public void processGroupImports() {
			for (DeferredImportSelectorGrouping grouping : this.groupings.values()) {
				Predicate<String> exclusionFilter = grouping.getCandidateFilter();
        //遍历放入到grouping中的group,并执行getImports()方法,此方法就是SPI调用点!!!!
				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);
					}
				});
			}
		}

19.org.springframework.context.annotation.ConfigurationClassParser.DeferredImportSelectorGrouping#getImports 方法

public Iterable<Group.Entry> getImports() {
			for (DeferredImportSelectorHolder deferredImport : this.deferredImports) {
            // 调用group的process方法
		    this.group.process(deferredImport.getConfigurationClass().getMetadata(),
						deferredImport.getImportSelector());
			}
			return this.group.selectImports();
		}

20.org.springframework.boot.autoconfigure.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()));
           // 调用getAutoConfigurationEntry
			AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
					.getAutoConfigurationEntry(annotationMetadata);
			this.autoConfigurationEntries.add(autoConfigurationEntry);
			for (String importClassName : autoConfigurationEntry.getConfigurations()) {
				this.entries.putIfAbsent(importClassName, annotationMetadata);
			}
		}

如上所示,最终来到

21.org.springframework.boot.autoconfigure.AutoConfigurationImportSelector#getAutoConfigurationEntry

该方法可以从spring.factories读取相应配置。

============以上是分析如何从spring.factories中加载XXXAutoConfigration的过程============

好,我们继续。

============以下是将configClasses中的XXXAutoConfigration注册为Bean的过程============

22.回到步骤11.org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitions

public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
        ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator = new ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator();
        Iterator var3 = configurationModel.iterator();

        while(var3.hasNext()) {
            ConfigurationClass configClass = (ConfigurationClass)var3.next();
            this.loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
        }

    }

23.org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForConfigurationClass

private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, ConfigurationClassBeanDefinitionReader.TrackedConditionEvaluator trackedConditionEvaluator) {
        if (trackedConditionEvaluator.shouldSkip(configClass)) {
            // 此处打上断点configClass.getResource().toString().contains("Rabbit")
            String beanName = configClass.getBeanName();
            if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
                this.registry.removeBeanDefinition(beanName);
            }

            this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
        } else {
            // 此处打上断点configClass.getResource().toString().contains("Rabbit")
            if (configClass.isImported()) {
                this.registerBeanDefinitionForImportedConfigurationClass(configClass);
            }

            Iterator var3 = configClass.getBeanMethods().iterator();
            
            while(var3.hasNext()) {
                BeanMethod beanMethod = (BeanMethod)var3.next();
                //这里处理对应的@Bean方法 !!!!!!!!!!!!!!!!!!!!
                this.loadBeanDefinitionsForBeanMethod(beanMethod);
            }

            this.loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
            this.loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
        }
    }

执行完this.registerBeanDefinitionForImportedConfigurationClass(configClass);看目前的BeanNames

24.继续org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod

private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
        
                //注册
                this.registry.registerBeanDefinition(beanName, beanDefToRegister);
        
    }

注册完成以后效果

============以上是将configClasses中的XXXAutoConfigration注册为Bean的过程============

可以看到,不仅RabbitAutoConfiguration中的RabbitConnectionFactoryCreator成功注册,rabbitconnectionFactory也进行了注册(rabbitConnectionFactory的注册时机在哪里困扰了博主很久,在这里恍然大悟)。

实例化具体过程参考: Spring源码解析(五)IOC源码

以上就是SpringBoot自动装配的全部过程。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,可以得出以下结论: Spring Boot的自动装配原理可以通过查看spring.factories文件来了解。该文件位于spring-boot-autoconfigure-2.5.4.jar包的META-INF目录下。在启动过程中,Spring Boot会根据spring.factories文件中配置的自动配置类的全类名来加载对应的配置类。如果配置类中的@ConditionalOnxxx注解满足条件,则会加载该配置类。\[1\] 如果想深入了解自动装配原理,可以在源码中进行跟踪和研究。了解自动装配后,可以更好地理解yaml配置的过程,并在源码中找到可以配置的属性。\[3\] 在学习Spring Boot之前,建议先具备Spring和Spring MVC的基础知识。Spring Boot的目的是简化新Spring应用的搭建和开发过程,它使用特定的配置方式,使开发人员不再需要定义样板化的配置。\[4\] 对于集成特定模块,比如Freemarker,Spring Boot提供了自动集成的功能。只需要导入相应的starter包,就会自动实现注入。例如,集成Freemarker可以通过导入FreeMarkerAutoConfiguration来实现。\[5\] 综上所述,Spring Boot的自动装配原理可以通过查看spring.factories文件来了解,同时可以在源码中进行深入研究。在学习之前,建议具备Spring和Spring MVC的基础知识。对于特定模块的集成,Spring Boot提供了自动集成的功能。 #### 引用[.reference_title] - *1* [springboot自动装配原理笔记一](https://blog.csdn.net/JieZhongBa/article/details/120378592)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *4* *5* [导图梳理springboot手动、自动装配,让springboot不再难懂](https://blog.csdn.net/b644ROfP20z37485O35M/article/details/102029574)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [SpringBoot思维导图(知识点总结)](https://blog.csdn.net/weixin_38378034/article/details/115432455)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值