SpringBoot系列:自动装配原理分析

序言

不管在工作中还是在求职面试中,SpringBoot成为了我们必会的知识技能之一。当然,作为Spring Boot的精髓,自动配置原理首当其冲。在本文章的下面,也是自己在源代码中挣扎的一些简单理解。

思维导图

在这里插入图片描述

原理分析

  • 首先打开一个基本的springboot项目,我们可以看到@SpringBootApplication,说明这个类是SpringBoot的应用。SpringBoot就会运行这个类的main方法来启动SpringBoot项目:
    在这里插入图片描述

  • 点进去@SpringBootApplication注解,我们可以看到:
    在这里插入图片描述

  • 首先我们点进去看一下@SpringBootConfiguration注解,表明该类是一个Spring的配置类:
    在这里插入图片描述
    在点进去@Configuration看一下,可以看到Spring的配置类也是Spring的一个组件:
    在这里插入图片描述

  • 记下来我们点开@EnableAutoConfiguration,进入自动配置的注解:
    在这里插入图片描述
    我们首下看一下@AutoConfigurationPackage注解:
    在这里插入图片描述
    可以看到在这里主要是使用的@Import来给Spring容器中导入一个组件 ,这里导入的是Registrar.class,我们点进去看一下:

    	/**
    	 * {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
    	 * configuration.
    	 */
    	static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    
    		@Override
    		public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
    			register(registry, new PackageImport(metadata).getPackageName());
    		}
    
    		@Override
    		public Set<Object> determineImports(AnnotationMetadata metadata) {
    			return Collections.singleton(new PackageImport(metadata));
    		}
    
    	}
    

    就是通过registerBeanDefinitions这个方法获取扫描的包路径,我们可以debug看看:
    在这里插入图片描述从上图我们可以看到new PackageImport(metadata).getPackageName()可以获取到扫描的包路径,那么我们再看一下这个metadata是什么?
    在这里插入图片描述
    可以看到是标注在@SpringBootApplication注解上的DemosbApplication,也就是我们的主配置类,说白了就是将主配置类(即@SpringBootApplication标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。所以再这里包名一定要注意。

  • 到现在,包扫描路径获取到了,那具体加载哪些组件呢,我们看一下@Import(AutoConfigurationImportSelector.class),通过@Import注解就是给Spring容器中导入组件AutoConfigurationImportSelector,我们可以点进去看一下:

    	@Override
    	public String[] selectImports(AnnotationMetadata annotationMetadata) {
    		if (!isEnabled(annotationMetadata)) {
    			return NO_IMPORTS;
    		}
    		AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
    				.loadMetadata(this.beanClassLoader);
    		AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,
    				annotationMetadata);
    		return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());
    	}
    

    上面代码中loadmetadata的方法是加载项目的基本配置数据信息,而getAutoConfigurationEntry方法则是自动装配的逻辑,继续点进去:

    /**
    	 * Return the {@link AutoConfigurationEntry} based on the {@link AnnotationMetadata}
    	 * of the importing {@link Configuration @Configuration} class.
    	 * @param autoConfigurationMetadata the auto-configuration metadata
    	 * @param annotationMetadata the annotation metadata of the configuration class
    	 * @return the auto-configurations that should be imported
    	 */
    	protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
    			AnnotationMetadata annotationMetadata) {
    			//自动装配的开关,如果没有返回null
    		if (!isEnabled(annotationMetadata)) {
    			return EMPTY_ENTRY;
    		}
    		AnnotationAttributes attributes = getAttributes(annotationMetadata);
    		//获取候选配置
    		List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
    		configurations = removeDuplicates(configurations);
    		Set<String> exclusions = getExclusions(annotationMetadata, attributes);
    		checkExcludedClasses(configurations, exclusions);
    		configurations.removeAll(exclusions);
    		configurations = filter(configurations, autoConfigurationMetadata);
    		fireAutoConfigurationImportEvents(configurations, exclusions);
    		return new AutoConfigurationEntry(configurations, exclusions);
    	}
    

    这时我们可以在getAutoConfigurationEntry中打一个DeBug,看看:

    在这里插入图片描述
    可以看到通过getCandidateConfigurations这个方法是获取候选的配置,我们点进去看看:

    	/**
    	 * Return the auto-configuration class names that should be considered. By default
    	 * this method will load candidates using {@link SpringFactoriesLoader} with
    	 * {@link #getSpringFactoriesLoaderFactoryClass()}.
    	 * @param metadata the source metadata
    	 * @param attributes the {@link #getAttributes(AnnotationMetadata) annotation
    	 * attributes}
    	 * @return a list of candidate configurations
    	 */
    	protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
    		List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
    				getBeanClassLoader());
    		Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
    				+ "are using a custom packaging, make sure that file is correct.");
    		return configurations;
    	}
    

    我们看一下loadFactoryNames,点进去:
    在这里插入图片描述
    到这里基本清楚了,springboot的自动装配就是通过自定义实现ImportSelector接口,从而导致项目启动时会自动将所有项目META-INF/spring.factories路径下的配置类注入到spring容器中,从而实现了自动装配。
    在这里插入图片描述
    J2EE的整体整合解决方案和自动配置都在spring-boot-autoconfigure-2.2.12.RELEASE.jar

小结

多看源码,debug调试

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值