SpringBoot2.3.x 自动配置原理

下面关于SpringBoot2.3.x 自动配置原理的介绍,纯属自己的见解,如有不恰当之处,请留言指正。
SpringBoot在启动时会去依赖的Starter包中寻找resources/META-INF/spring.factories文件,然后根据文件中配置的jar包去扫描项目所依赖的jar包。根据spring.factories配置加载AutoConfigure类,根据@Conditional注解的条件,进行自动配置并将Bean注入Spring Context中,供项目启动成功后使用。

@SpringBootApplication 注解

在某个类上加上@SpringBootApplication注解,则说明:

  • 这个类是 SpringBoot 的主配置类。
  • SpringBoot 就应该运行这个类的 main 方法来启动 SpringBoot 应用。

看下该注解的源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
   //省略相关代码
}

可以看到 SpringBootApplication 注解是一个组合注解,其主要组合了一下三个注解:

  • @SpringBootConfiguration:该注解表示这是一个 SpringBoot 的配置类,其实它就是一个 @Configuration 注解而已。
  • @ComponentScan:开启组件扫描。
  • @EnableAutoConfiguration:就是这个类开启的自动配置。

@EnableAutoConfiguration 注解

@EnableAutoConfiguration 注解的源码如下:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {

	String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

	/**
	 * Exclude specific auto-configuration classes such that they will never be applied.
	 * @return the classes to exclude
	 */
	Class<?>[] exclude() default {};

	/**
	 * Exclude specific auto-configuration class names such that they will never be
	 * applied.
	 * @return the class names to exclude
	 * @since 1.3.0
	 */
	String[] excludeName() default {};

}

可以看到@EnableAutoConfiguration 注解由@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)组合而成,通过打断点发现:先执行@Import(AutoConfigurationImportSelector.class)注解,然后执行@AutoConfigurationPackage注解。

@Import(AutoConfigurationImportSelector.class)

下面看下AutoConfigurationImportSelector.class导入后是如何执行的,SpringBoot项目启动后,执行到下面的方法:
在这里插入图片描述
我们看到获取自动配置类数组的方法是getAutoConfigurationEntry(annotationMetadata):
在这里插入图片描述
然后由getCandidateConfigurations(annotationMetadata, attributes)方法获取自动配置类的完整类路径并放入list中:
在这里插入图片描述
我们看到了获取自动配置类的完整类路径的list是由SpringFactoriesLoader的loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
getBeanClassLoader())方法来完成的,其中getSpringFactoriesLoaderFactoryClass()方法:
在这里插入图片描述
就是获取EnableAutoConfiguration这个注解。
在这里插入图片描述
我们看到loadFactoryNames这个方法调用了loadSpringFactories(classLoader):
在这里插入图片描述
首先从缓存中获取自动配置类的完整类路径,如果为空,则通过classLoader.getResources(FACTORIES_RESOURCE_LOCATION)方法转成Properties后获取,最后再放入到缓存中,其中,FACTORIES_RESOURCE_LOCATION:
“META-INF/spring.factories”。即:

  • 从当前项目的类路径中获取所有 META-INF/spring.factories 这个文件下的信息。
  • 将上面获取到的信息封装成一个 Map 返回。
  • 从返回的 Map 中通过刚才传入的 EnableAutoConfiguration.class 参数,获取该 key 下的所有值。
META-INF/spring.factories

我们来看一下 META-INF/spring.factories 这类文件是什么。当然在很多第三方依赖中都会有这个文件,一般每导入一个第三方的依赖,除了本身的jar包以外,还会有一个 xxx-spring-boot-autoConfigure,这个就是第三方依赖自己编写的自动配置类。我们现在就以 spring-boot-autocongigure 这个依赖来说。
在这里插入图片描述
可以看到 EnableAutoConfiguration 下面有很多类,这些就是我们项目进行自动配置的类。

到这里,AutoConfigurationImportSelector.class就完成了将类路径下 META-INF/spring.factories 里面配置EnableAutoConfiguration 的全路径类加入到 Spring 容器中。然后开始执行selectImports():
在这里插入图片描述
这个方法的作用就是查找导入的自动配置类并进行排序后返回。
然后我们看看@AutoConfigurationPackage

@AutoConfigurationPackage

从字面意思理解就是自动配置包。点进去可以看到就是一个 @Import 注解:@Import({Registrar.class}),导入了一个 Registrar 的组件。
在这里插入图片描述
然后getPackageNames()方法点进去之后:
在这里插入图片描述
可以看到返回了一个包名,该包名其实就是主配置类所在的包。然后点击register方法进去:
在这里插入图片描述
打断点发现:BeanDefinitionRegistry就是DefaultListableBeanFactory,如果这里面的beanDefinitionMap不包含“org.springframework.boot.autoconfigure.AutoConfigurationPackages”,则new一个GenericBeanDefinition为beanDefinition,并将“主配置类所在的包路径”set进去,然后以“org.springframework.boot.autoconfigure.AutoConfigurationPackages”为beanName,刚才新建的beanDefinition为BeanDefinition放入到DefaultListableBeanFactory的beanDefinitionMap中。register方法执行结束后,可以看到:
在这里插入图片描述
故@AutoConfigurationPackage 注解就是将主配置类(@SpringBootConfiguration标注的类)的所在包及下面所有子包里面的所有组件扫描到Spring容器中。
register方法执行结束后,接着往下执行,可以看到:
在这里插入图片描述
继续向下执行:
在这里插入图片描述
继续执行,可以看到进入到了AbstractApplicationContext的refresh()方法中,即ServletWebServerApplicationContext的refresh()方法,
在这里插入图片描述
而这个refresh()方法最终是由SpringApplication的refresh方法调用:
在这里插入图片描述
可以看到这里是AnnotationConfigServletWebServerApplicationContext的DefaultListableBeanFactory中的beanDefinitionMap里面由362(数字和你的项目有关)个beanDefinition。继续走:
在这里插入图片描述
从上图中可以看到,是由SpringApplication的refreshContext()方法执行调用的,最终执行到了:
在这里插入图片描述
到这SpringBoot的自动配置就结束了,即META-INF/spring.factories中的自动配置类和主配置类(@SpringBootConfiguration标注的类)的所在包及下面所有子包里面的所有类都加载到AnnotationConfigServletWebServerApplicationContext的DefaultListableBeanFactory中的beanDefinitionMap里面。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值