Spring Boot自动配置揭秘

在学习完 Spring Boot 后,我们了解到创建一个 Spring Boot 项目只需通过引入相应的 Maven 依赖,就能快速启动一个 Java 应用,而无需繁琐的 XML 配置。那么,Spring Boot 是如何实现这一点的呢?

首先,在 pom.xml 中引入 Spring Boot 的依赖,例如

xml 复制代码
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

启动类

java 复制代码
@SpringBootApplication
public class SpringBootStart01Application {

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

可以看到,Spring Boot 项目只需一个 @SpringBootApplication 注解和调用 SpringApplication.run() 方法即可启动。

一、@SpringBootApplication

@SpringBootApplication 注解实际上是多个注解的组合,其中最重要的三个是:

  • @SpringBootConfiguration:标识这是一个 Spring Boot 配置类。
  • @EnableAutoConfiguration:启用自动配置功能。
  • @ComponentScan:启用组件扫描,自动扫描当前包及其子包中的 Spring 组件

1.1@SpringBootConfiguration

字面意思可以得知,该注解表明当前类是一个 Spring Boot 配置类,Spring 会在启动时加载这个类中的配置。

二、@EnableAutoConfiguration

该注解是自动配置的核心,结合了 @AutoConfigurationPackage@Import 注解,导入 AutoConfigurationImportSelector 类。

2.1@AutoConfigurationPackage

  • 作用:将主配置类所在的包作为自动配置的基础包。
  • 实现 :通过 @Import 注解引入 AutoConfigurationPackages.Registrar,确保启动类所在的包被包含在自动配置的搜索范围内。

我们进入到Register 可以看到这个内部类实现了ImportBeanDefinitionRegistrar接口,就可以被注解@Import导入到spring容器里。

当 Spring 解析 @Import 注解时,它会检查注解中指定的类是否实现了 ImportBeanDefinitionRegistrar 接口。

如果实现了该接口,Spring 将不会创建这些类的实例,而是将它们保存起来,并稍后调用其 registerBeanDefinitions 方法。

在 registerBeanDefinitions 方法中,可以通过 BeanDefinitionRegistry 参数来注册新的 BeanDefinition 对象到 Spring 容器中。(下面有关于该接口的案例)

通过debug可以看出(String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0])的值为当前启动类所在的包名

可以得出:@AutoConfigurationPackage 就是将主配置类(@SpringBootApplication 标注的类)所在的包下面所有的组件都扫描注冊到 spring 容器中。

2.1.2 ImportBeanDefinitionRegistrar接口

这个接口配合@Import注解向容器中注册Bean对象

案例:

  • 定义一个user对象

  • 定义MyImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口注册bean对象

java 复制代码
public class MyImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        //获取user的对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(User.class).getBeanDefinition();
        //注册id为user的对象
        registry.registerBeanDefinition("user",beanDefinition);
    }
  • 导入注册类
java 复制代码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MyImportBeanDefinitionRegister.class)
public @interface EnableUser {
}
  • 启动类
java 复制代码
@SpringBootApplication
public class SpringBootDemo0401Application {

    public static void main(String[] args) {
        ConfigurableApplicationContext run = SpringApplication.run(SpringBootDemo0401Application.class, args);
        User bean = run.getBean(User.class);
        System.out.println(bean);
    }

}

结果:

2.2AutoConfigurationImportSelector类!!!

AutoConfigurationImportSelector 是自动配置的关键类。其主要功能是选择需要导入的自动配置类。

  1. 选择配置类 :通过 selectImports() 方法确定需要导入的自动配置类。
  1. 加载配置条目 :调用 getAutoConfigurationEntry() 方法来加载自动配置类的元数据。

集合configurations长度为145,所以共有145个配置类可以选择,在使用时返回对应需要的配置类

  1. 解析配置类 :通过 getCandidateConfigurations() 方法从 spring.factories 文件中加载所有可用的自动配置类。

我们进入到getCandidateConfigurations()方法中可以看到是使用SpringFactoriesLoader从spring.factories文件中加载指定类型的工厂类名,然后通过ImportCandidates.load方法加载所有AutoConfiguration类,并将这些类名添加到列表中

  1. spring.factories文件

spring.factories 文件是 Spring Boot 自动配置的重要配置文件,定义了所有的自动配置类。Spring Boot 通过这个文件来加载和注册自动配置类。

总结:

Spring Boot 的自动配置机制通过 @EnableAutoConfiguration 注解和 AutoConfigurationImportSelector 类,实现了对 spring.factories 文件中定义的自动配置类的智能加载。这种机制允许开发者专注于业务逻辑,而无需过多关注基础框架配置,极大地提高了开发效率和代码可维护性。

通过本文的介绍,你应该能够更好地理解 Spring Boot 自动配置背后的技术细节,并能更加高效地利用这一特性来构建自己的应用

spring.factories 文件中定义的自动配置类的智能加载。这种机制允许开发者专注于业务逻辑,而无需过多关注基础框架配置,极大地提高了开发效率和代码可维护性。

通过本文的介绍,你应该能够更好地理解 Spring Boot 自动配置背后的技术细节,并能更加高效地利用这一特性来构建自己的应用

相关推荐
计算机小白一个1 分钟前
蓝桥杯 Java B 组之岛屿数量、二叉树路径和(区分DFS与回溯)
java·数据结构·算法·蓝桥杯
孤雪心殇2 分钟前
简单易懂,解析Go语言中的Map
开发语言·数据结构·后端·golang·go
White graces14 分钟前
正则表达式效验邮箱格式, 手机号格式, 密码长度
前端·spring boot·spring·正则表达式·java-ee·maven·intellij-idea
菠菠萝宝15 分钟前
【Java八股文】10-数据结构与算法面试篇
java·开发语言·面试·红黑树·跳表·排序·lru
不会Hello World的小苗22 分钟前
Java——链表(LinkedList)
java·开发语言·链表
Allen Bright1 小时前
【Java基础-46.3】Java泛型通配符详解:解锁类型安全的灵活编程
java·开发语言
柃歌1 小时前
【UCB CS 61B SP24】Lecture 7 - Lists 4: Arrays and Lists学习笔记
java·数据结构·笔记·学习·算法
柃歌1 小时前
【UCB CS 61B SP24】Lecture 4 - Lists 2: SLLists学习笔记
java·数据结构·笔记·学习·算法
是姜姜啊!1 小时前
redis的应用,缓存,分布式锁
java·redis·spring
梨落秋溪、2 小时前
输入框元素覆盖冲突
java·服务器·前端