当前位置: 首页 > news >正文

SpringBoot 自动配置

约定大于配置

SpringBoot 自动配置的关键概念:约定大于配置

“约定大于配置”(Convention over Configuration)是一种软件设计原则,强调减少开发者需要进行的配置工作,而是通过约定的默认设置来使开发变得更加简洁。

旨在通过预先定义合理的默认行为和约定,减少开发者需要手动编写的配置。其核心思想是:“如果你遵循框架的约定,就无需显式配置;只有需要偏离约定时,才需要额外配置”

主要思想

  • 默认约定:制定了一些列默认的规则和约定
  • 配置的最小化:尽量减少开发者需要进行的显式配置,将配置的工作交给框架或者工具来完成
  • 统一规范:使用广泛的共同约定,使得开发者能够遵循一致的开发模式

如何体现

  • 项目结构约定
    • 默认目录结构:src/main/java 存放源代码,src/main/resources 存放资源文件,启动类位于根包下,SpringBoot 会自动扫描其子包中的组件
    • 启动类位于根包下是,SpringBoot 会自动扫描其子包中的组件
  • 自动配置
    • 条件发 Bean 加载:若引入  spring-boot-starter-web,自动配置 Tomcat 和 Spring MVC
    • 覆盖默认配置:通过 application 配置文件来覆盖默认配置
  • 配置文件约定
    • 默认配置文件:配置文件为 application.yamlapplication.properties
    • 环境差异化配置:通过  application-dev.properties(开发环境)和  application-prod.properties(生产环境)区分配置,无需代码修改,只需激活对应 Profile

JavaConfig 配置方式

JavaConfig 是 Spring 框架中一种基于 Java 的配置方式,旨在替代传统的 XML 配置。通过使用注解和 Java 类,开发者可以用更简洁、类型安全且面向对象的方式定义 Spring 容器的 Bean 和依赖关系。

核心概念:使用注释来描述 Bean 配置的组件

核心作用

  • 取代 XML:用 Java 代码替代 XML,减少配置文件的冗余
  • 类型安全:编译时检查配置的正确性,避免 XML 中的字符串拼写错误
  • 面向对象优势:支持继承、多态等特性,便于复用和模块化配置
  • 与注解驱动开发结合:无缝整合  @Component@Autowired  等注解,简化依赖注入

核心注解

  • @Configuration:标记一个类为配置类,Spring 会将其视为 Bean 定义的来源
  • @Bean:在配置类中标记方法,方法的返回值会被注册为 Spring Bean
  • @ComponentScan:自动扫描指定包下的组件(如  @Component@Service  等注解标记的类)
  • @Import:引入其他配置类,实现模块化配置

总结

  • 通过 @configuration 注解的配置类创建哪些 Bean
  • 通过条件注解来满足创建条件
  • 通过配置属性来创建 Bean 的属性

自动配置原理

可以根据启动类中的 @SpringBootApplication 核心注解来详细解释自动化配置原理

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

点击 @SpringBootApplication 注解看到该注解组成,可以发现 @SpringBootApplication 注解是组合注解,其中 @SpringBootConfiguration@EnableAutoConfiguration 以及 @ComponentScan 这三个注解最为重要

  • @SpringBootConfiguration:继承自 Configuration,支持 JavaConfig 的方式进行配置
  • @EnableAutoConfiguration:用于开启自动配置
  • @ComponentScan:自动扫描组件,默认扫描该类所在包及其子包下所有带有指定注解的类,将它们自动装配到bean容器中,会被自动装配的注解包括@Controller、@Service、@Component、@Repository等。也可以指定扫描路径
@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 {}

@SpringBootConfiguration

实际上是一个特殊的 @Configuration 注解,标注在某类上,说明该类为 SpringBoot 的配置类

直接使用 @Configuration 注解并不会有太多与 SpringBoot 特定的功能整合,@SpringBootConfiguration 注解的出现更多的是为了标明这是一个由 SpringBoot 管理的配置类,@Configuration是Spring下的配置类注解,@SpringBootConfiguration是SpringBoot下的配置类注解,但二者的本质相同

@EnableAutoConfiguration

先看 @EnableAutoConfiguration 注解的源码

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

注解源码中可以看到 @Import(AutoConfigurationImportSelector.class) 注解,这个注解的作用:

  • ImportSelector  是 Spring 提供的接口,用于动态选择需要导入的配置类,也就是不需要 new 对象,也不需要给这个对象加上任何注解,直接使用该类皆可
  • 也就是在 @EnableAutoConfiguration 中将 AutoConfigurationImportSelector 配置类注入到了 Spring 容器中,使得可以直接使用这些类
  • AutoConfigurationImportSelector  实现了  DeferredImportSelector(延迟导入),确保自动配置类在所有其他配置类处理完成后加载

AutoConfigurationImportSelector 类中主要分析 selectImports 方法,在启动时会调用 selectImports 方法,返回需要加载的自动配置类列表

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {@Override//作用就是Spring会把这个方法返回的数组中所有全限定名的类注入到Spring容器中public String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}// 加载所有候选自动配置类AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(annotationMetadata);// 返回最终生效的配置类return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
}

selectImports 方法中最关键就是 getAutoConfigurationEntry 方法,因此需要重点分析这个方法

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {// 检查自动配置功能是否开启,默认开启if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}AnnotationAttributes attributes = getAttributes(annotationMetadata);// 获取候选配置类List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);// 去除重复的配置类configurations = removeDuplicates(configurations);// 获得注解中被exclude和excludeName排除的类的集合Set<String> exclusions = getExclusions(annotationMetadata, attributes);// 检查被排除类是否可实例化、是否被自动注册配置所使用,不符合条件则抛出异常checkExcludedClasses(configurations, exclusions);configurations.removeAll(exclusions);// 过滤configurations = getConfigurationClassFilter().filter(configurations);// 将配置类和排除类通过事件传入到监听器中fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}
}

getCandidateConfigurations 方法中时获取候选配置类,根据报错信息中可以看出,配置文件存放在 org.springframework.boot.autoconfigure.AutoConfiguration.imports

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {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 方法的 String.format("META-INF/spring/%s.imports", annotation.getName()) 中可以找出自动配置文件的路径

public final class ImportCandidates implements Iterable<String> {public static ImportCandidates load(Class<?> annotation, ClassLoader classLoader) {Assert.notNull(annotation, "'annotation' must not be null");ClassLoader classLoaderToUse = decideClassloader(classLoader);String location = String.format("META-INF/spring/%s.imports", annotation.getName());Enumeration<URL> urls = findUrlsInClasspath(classLoaderToUse, location);List<String> importCandidates = new ArrayList();while(urls.hasMoreElements()) {URL url = (URL)urls.nextElement();importCandidates.addAll(readCandidateConfigurations(url));}return new ImportCandidates(importCandidates);}
}

自动配置文件

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
......

参考

  • 芋道 Spring Boot 自动配置原理 | 芋道源码 —— 纯源码解析博客
  • Spring Boot 自动配置原理懂后轻松写一个自己的 starter - 程序员 xiaozhang - 博客园
  • @SpringBootApplication和@SpringBootConfiguration的关系 - 文采杰出 - 博客园

相关文章:

  • FEKO许可证与其他电磁仿真软件的比较
  • 2024年热门AI趋势及回顾
  • leetcode 3355. 零数组变换 I 中等
  • PYTHON训练营DAY31
  • ⼆叉搜索树详解
  • 迅为RK3562开发板旋转Uboot logo和内核logo
  • string在c语言中代表什么(非常详细)
  • VitePress 中以中文字符结尾的字体加粗 Markdown 格式无法解析
  • 嵌入式学习笔记 D24 :系统编程之i/o操作
  • PyTorch 之 torch.distributions.Categorical 详解
  • MATLAB中进行语音信号分析
  • USB学习【13】STM32+USB接收数据过程详解
  • 关于element-ui的table type=“expand“ 嵌套表格展开异常问题解决方案
  • CYT4BB Dual Bank 1 - 存储机制
  • 02 基本介绍及Pod基础排错
  • P/Invoke 内存资源处理方案
  • Linux bash shell的循环命令for、while和until
  • C++面向对象——多态
  • 单片机复用功能重映射Remap功能
  • 基于单片机的车辆防盗系统设计与实现
  • 广东茂名信宜出现龙卷,一家具厂铁皮房受损
  • 最高法:政府信息公开案件审理应避免泄露国家秘密、商业秘密
  • 王毅将出席《关于建立国际调解院的公约》签署仪式
  • 这位中国电影早期的全能奇才,90年前唱响国歌
  • 持续降雨存在落石风险,贵州黄果树景区水帘洞将封闭至6月初
  • 台湾关闭最后的核电,岛内担忧“非核家园”缺电、涨电价困局难解