【SpringBoot】自动配置原理

embedded/2024/9/24 10:18:14/

Spring Boot 自动配置原理是 Spring Boot 提供简化 Spring 应用程序开发的核心特性之一。

它使得开发者无需编写大量的配置代码就能让应用程序具有很多常见的功能。

以下是 Spring Boot 自动配置的基本原理和工作流程:

  1. 通过 @SpringBootConfiguration 引入了 @EnableAutoConfiguration(负责启动自动配置功能)

  2. @EnableAutoConfiguration 引入了 @lmport

  3. Spring 容器启动时:加载 loc 容器时会解析 @Import 注解

  4. @Import 导入了一个 deferredlmportSelector,它会使 SpringBoot 的自动配置类的顺序在最后,这样方便我们扩展和覆盖

  5. 然后读取所有的 /META-INF/spring.factories 文件(伪 SPI)

  6. 过滤出所有 AutoConfigurtionClass 类型的类

  7. 最后通过 @Condition 排除无效的自动配置类

 

下面我们在通过源码走一遍上述的流程:

1、找到项目的启动类

java">@SpringBootApplication
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}

2、进入 @SpringBootApplication  注解

java">@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 {......
}

3、进入 @EnableAutoConfiguration

java">@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";Class<?>[] exclude() default {};String[] excludeName() default {};
}

4、进入 AutoConfigurationImportSelector.class  

java">public class AutoConfigurationImportSelector implements  DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {......}

5、找到 selectImports(AnnotationMetadata annotationMetadata) 方法  

java">public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!this.isEnabled(annotationMetadata)) {return NO_IMPORTS;} else {AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
}

6、进入 this.getAutoConfigurationEntry(annotationMetadata)

java">protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {// 检查自动配置功能是否开启,默认开启if (!this.isEnabled(annotationMetadata)) {return EMPTY_ENTRY;} else {// 加载自动配置的元信息AnnotationAttributes attributes = this.getAttributes(annotationMetadata);// 获取候选配置类List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);// 去重configurations = this.removeDuplicates(configurations);// 获得注解中被 exclude 和 excludeName 排除的类的集合Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);// 检查被排除类是否可实例化、是否被自动注册配置所使用,不符合条件则抛出异常this.checkExcludedClasses(configurations, exclusions);// 从候选配置类中去除掉被排除的类configurations.removeAll(exclusions);// 过滤configurations = this.getConfigurationClassFilter().filter(configurations);// 将配置类和排除类通过事件传入到监听器中this.fireAutoConfigurationImportEvents(configurations, exclusions);// 最终返回符合条件的自动配置类的全限定名数组return new AutoConfigurationEntry(configurations, exclusions);}
}

7、进入 this.getCandidateConfigurations(annotationMetadata, attributes)

依据 getSpringFactoriesLoaderFactoryClass() 返回的 key 在 spring.factories 中找到该 key 对应的 value(到这里就可以得到候选配置类)

java">protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.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;
}protected Class<?> getSpringFactoriesLoaderFactoryClass() {return EnableAutoConfiguration.class;
}
javascript"># Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,\
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,\
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,\
org.springframework.boot.autoconfigure.context.ConfigurationPropertiesAutoConfiguration,\
......

8、获取到候选配置类后,会经过去重、排除、过滤等操作,最终会通过 selectImports() 方法返回一个自动配置类的全限定名数组

9、得到了一个动态配置类的全限定名数组后,这些配置类需要在满足 @Condition 后才能真正的被注册到 Spring 容器之中

注解说明
@ConditionOnBean在容器中有指定 Bean 的条件下
@ConditionalOnMissingBean在容器中没有指定 Bean 的条件下
@ConditionOnClass在 classpath 类路径下有指定类的条件下
@ConditionalOnMissingClass在 classpath 类路径下没有指定类的条件下
@ConditionalOnResource类路径是否有指定的值
@ConditionalOnWebApplication在项目是一个 Web 项目的条件下
@ConditionOnProperty在指定的属性有指定的值条件下
@ConditionalOnExpression当表达式为 true 的时候,才会实例化这个 Bean
@AutoConfigureAfter在某个 Bean 完成自动配置后实例化这个 Bean
@AutoConfigureBefore在某个 Bean 完成自动配置前实例化这个 Bean

 

getCandidateConfigurations() 方法如何获取 spring.factories 的路径?

getCandidateConfigurations() 方法中调用了 SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());

其中的 loadSpringFactories() 方法,该方法中会加载类路径下的 META-INF/spring.factories 文件

java">public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {ClassLoader classLoaderToUse = classLoader;if (classLoaderToUse == null) {classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();}String factoryTypeName = factoryType.getName();return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {Map<String, List<String>> result = (Map)cache.get(classLoader);if (result != null) {return result;} else {Map<String, List<String>> result = new HashMap();try {Enumeration<URL> urls = classLoader.getResources("META-INF/spring.factories");......}}   
}

 

自动配置类还会绑定到 application.propertiesapplication.yml 中的属性。

Spring Boot 通过 @ConfigurationProperties 注解将配置文件中的属性绑定到 Java Bean 上。

可以通过在配置文件中设置特定的属性来调整自动配置的行为,或者通过提供自己的实现来覆盖默认的自动配置。

Spring Boot 的自动配置机制是为了减少开发者的配置负担,使开发者能够更专注于业务逻辑的实现。

它通过条件注解来智能地决定哪些配置应该启用,并且可以很容易地被覆盖和扩展。

 

一  叶  知  秋,奥  妙  玄  心


http://www.ppmy.cn/embedded/105396.html

相关文章

net、udp、tcp

Makefile的main.c文件中的全局变量SONG song,要在fun.c文件里面写成extern SONG song 编译方法 第一次编写 或 网络编程 物理层的网线规定有八根,颜色不一样,功能不一样,光猫把光信号转换成电信号,光纤10Gb WiFi叫无线局域网,一般也就50米左右,手机流量叫蜂窝网络,…

数据库水平分表方案

数据库分表有很多策略&#xff0c;如下&#xff1a; 数据库分表是处理大型数据库中数据量过大的一种常见策略&#xff0c;它可以提高查询性能、减少锁竞争、降低维护成本等。以下是一些常见的数据库分表方案&#xff1a; 1. **垂直分表&#xff08;Vertical Partitioning&…

【Python机器学习】NLP词频背后的含义——隐性语义分析

隐性语义分析基于最古老和最常用的降维技术——奇异值分解&#xff08;SVD&#xff09;。SVD将一个矩阵分解成3个方阵&#xff0c;其中一个是对角矩阵。 SVD的一个应用是求逆矩阵。一个矩阵可以分解成3个最简单的方阵&#xff0c;然后对这些方阵求转置后再把它们相乘&#xff…

gitlab 包含模型文件,比较大,怎么上传

当你的 GitLab 项目包含较大的模型文件或其他大文件时&#xff0c;直接上传可能会遇到一些限制。你可以使用以下几种方法来处理&#xff1a; 方法 1&#xff1a;调整 Git 的文件大小限制 调整 GitLab 的限制&#xff1a; 如果你有权限管理 GitLab 实例&#xff0c;你可以调整 …

UDP英译汉网络词典

这里我们用UDP实现一个简单的英译汉小词典。我们还是仿照前一篇的UDP编程&#xff0c;将各自的组件封装起来&#xff0c;实现高内聚低耦合。 一. 字典翻译功能实现 首先我们将我们的字典知识库放在txt文本中。 apple: 苹果 banana: 香蕉 cat: 猫 dog: 狗 book: 书 pen: 笔 ha…

vue、小程序识别换行

vue 1、\n <pre></pre>标签识别返回的\n换行符&#xff0c;与css的 white-space: pre-wrap(保留空白符序列&#xff0c;但是正常地进行换行。);&#xff0c;pre-line(合并空白符序列&#xff0c;但是保留换行符。)注意代码中的换行也会被识别到&#xff0c;如果标…

String核心设计模式——建造者模式

目录 建造者模式 优点 缺点 使用场景 结构 步骤 1 Item.java Packing.java 步骤 2 Wrapper.java Bottle.java 步骤 3 Burger.java ColdDrink.java 步骤 4 VegBurger.java ChickenBurger.java Coke.java Pepsi.java 步骤 5 Meal.java 步骤 6 MealBuilder…

网络编程TCP和UDP

将TCP的CS模型再敲一遍 TCP服务器 1->创建原始的套接字描述符 2->将原始套接字与主机ip绑定 3->将原始套接字设置监听状态 4->接收客户端连接&#xff0c;获取客户端信息&#xff0c;因为原始套接字被用了&#xff0c;所以创建新的套接字描述符用于客户端通信…