【框架源码】SpringBoot核心源码解读之自动配置源码分析

简介: 【框架源码】SpringBoot核心源码解读之自动配置源码分析

SpringBoot流行之前,程序员大多是用SSM框架整合来进行WEB后端开发。这种方式非常麻烦,需要手动引入大量的包,还要配置很多XML文件,光是搭建环境就需要很久。

基于这种的SSM中xml配置的繁琐,后来衍生出SpringBoot。SpringBoot中的自动装载,大大简化了开发者对于配置的相关信息。

问题:什么是SpringBoot自动配置

  • 当spring容器启动后,一些自动配置类通过@Conditional注解自动装配的IOC容器中
  • 不需要手动去注入,简化了开发,省去了繁琐的配置
  • 自动配置的相关工作就在 @SpringBootApplication这个注解上

我们来看一下@SpringBootApplication这个注解。

@Target({ElementType.TYPE})  //注解的作用范围,用在类,接口,注解等上面
@Retention(RetentionPolicy.RUNTIME) //注解生命周期,runtime,保留在运行时期
@Documented //可以被文档化
@Inherited //可以被子类继承
@SpringBootConfiguration  //里面是@Configuration属于配置类
@EnableAutoConfiguration  //启动自动配置功能
//配置扫描包
@ComponentScan(
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication

@SpringBootApplication 是一个复合注解,由几个核心的注解组成。

  • @SpringBootConfiguration
  • 里面是 @Configuration,代表是一个配置类,说明主程序类也是一个配置类
  • @EnableAutoConfiguration
  • @AutoConfigurationPackage 将指定的一个包下的所有组件导入到容器当中
  • 在@AutoConfigurationPackage 注解中存在一个 @Import({Registrar.class}) 注解,自动配置包就是通过这个完成的。
  • @ComponentScan
  • 指定扫描哪些组件,默认是扫描主程序所在的包以及其子包
  • 它的核心在于@EnableAutoConfiguration这个注解,这里面是加载自动配置的类信息。

@EnableAutoConfiguration注解核心内容

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage //自动配置包
@Import(AutoConfigurationImportSelector.class) //通过import导入满足条件的bean,并加载到spring的ioc容器里面
public @interface EnableAutoConfiguration 

@AutoConfigurationPackage注解核心内容

  • Registrar的作用是扫描包,默认是把主类所在的包和子包里面全部类扫描进容器里面
  • 所以为什么开发springboot项目需要把主类放到最外层目录,不然就对的注解类就找不到
@Import(AutoConfigurationPackages.Registrar.class) //把Registrar导入到spring容器里面

核心逻辑为这段逻辑,一会我们会断点进行调试。

    //获取主程序所在的目录为位置,metadata是元注解信息
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata,
        BeanDefinitionRegistry registry) {
      register(registry, new PackageImport(metadata).getPackageName());
    }

下面,我们来看一下@Import(AutoConfigurationImportSelector.class)这个里面都做了哪些操作。其核心就是通过import导入满足条件的bean, 把springboot应用里面符合@Configuration的类,加载到spring的ioc容器里面

  //用于实现动态注册Bean的功能,【批量】导入对象到容器里,根据条件动态地选择需要注册的Bean,并加入Spring容器
  //实现ImportSelector接口,这个接口的selectImports方法会返回一个String数组,数组中的值就是要添加的组件的全类名
  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());
  }

ok,我们再来看一下getAutoConfigurationEntry()这个方法的逻辑。这个方法主要是根据指定的注解元数据获取自动配置的条目。

protected AutoConfigurationEntry getAutoConfigurationEntry(
      AutoConfigurationMetadata autoConfigurationMetadata,
      AnnotationMetadata annotationMetadata) {
    //判断是否启用了自动配置
    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);
  }

我们来看看getCandidateConfigurations()这里面核心逻辑就是去META-INF/spring.factories这个文件中去拉取全部的配置信息。

  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;
  }
  public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";

好的,接下来我们来调试走下源码流程。

a1f8bffd3e694ef3a37988a696dc9a28.jpg

987c568e8fb74e5d89d7b7aa24ca3c46.jpg

0262e2ac3d3f4bf196a98d85b29d1885.jpg

32e9efa28ee5450f82ca0f46d5c2a752.jpg


9fe6a8b9fcba4a8296584e3b54f1c8a3.jpg

2daf7353fbbe44a7bbbd069f3e7b3ec9.jpg


49d6b3f546f74d5bbe6ebccbd652033e.jpg


ca5fa536f36449209b0b840a7c48383e.jpg

0b8c6fc7fe9f45df8f5def188fab3c6b.jpg

c6659135d6a042e5a5496e46a6e14bbe.jpg

2400ac1c88f342efb4b2558a1967ccb8.jpg

4e027a709d5549bfa75f876683cc5e3b.jpg

ok,我们来总结一下,SpringBoot自动装载的全流程。


首先,加载一下元数据信息

获取需要自动装载的类的信息

判断是否启用了自动配置

获取候选自动配置类列表

获取需要排除的自动配置类列表

检查是否存在需要排除的自动配置类

将需要排除的类从自动配置类列表中移除

获取配置类过滤器,对候选自动配置类列表进行过滤

触发自动配置导入事件,并返回一个新的自动配置条目

注册Bean的定义列表


相关文章
|
1月前
|
XML 安全 Java
|
2月前
|
缓存 NoSQL Java
什么是缓存?如何在 Spring Boot 中使用缓存框架
什么是缓存?如何在 Spring Boot 中使用缓存框架
55 0
|
10天前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
10天前
|
Java Maven Spring
SpringBoot配置跨模块扫描问题解决方案
在分布式项目中,使用Maven进行多模块开发时,某些模块(如xxx-common)没有启动类。如何将这些模块中的类注册为Spring管理的Bean对象?本文通过案例分析,介绍了两种解决方案:常规方案是通过`@SpringBootApplication(scanBasePackages)`指定扫描路径;推荐方案是保持各模块包结构一致(如com.xxx),利用SpringBoot默认扫描规则自动识别其他模块中的组件,简化配置。
SpringBoot配置跨模块扫描问题解决方案
|
10天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
5天前
|
Java 开发者 Spring
理解和解决Spring框架中的事务自调用问题
事务自调用问题是由于 Spring AOP 代理机制引起的,当方法在同一个类内部自调用时,事务注解将失效。通过使用代理对象调用、将事务逻辑分离到不同类中或使用 AspectJ 模式,可以有效解决这一问题。理解和解决这一问题,对于保证 Spring 应用中的事务管理正确性至关重要。掌握这些技巧,可以提高开发效率和代码的健壮性。
32 13
|
17天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
67 14
|
20天前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
102 13
|
17天前
|
IDE Java 测试技术
互联网应用主流框架整合之Spring Boot开发
通过本文的介绍,我们详细探讨了Spring Boot开发的核心概念和实践方法,包括项目结构、数据访问层、服务层、控制层、配置管理、单元测试以及部署与运行。Spring Boot通过简化配置和强大的生态系统,使得互联网应用的开发更加高效和可靠。希望本文能够帮助开发者快速掌握Spring Boot,并在实际项目中灵活应用。
35 5
|
2月前
|
缓存 IDE Java
SpringBoot入门(7)- 配置热部署devtools工具
SpringBoot入门(7)- 配置热部署devtools工具
56 1
SpringBoot入门(7)- 配置热部署devtools工具