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

【Spring】SpringBoot自动注入原理分析,@SpringBootApplication、@EnableAutoConfiguration详解

文章目录

    • SpringBoot 原理分析
      • 源码阅读
      • @SpringBootApplication
        • 1. 元注解
        • 2. @SpringBootConfiguration
        • 3. @EnableAutoConfiguration
        • 4. @ComponentScan
      • @EnableAutoConfiguration 详解
          • @Import ({AutoConfigurationImportSelector. class})
          • @AutoConfigurationPacket
      • 总结
    • 总结

SpringBoot 原理分析

源码阅读

SpringBoot 是如何帮助我们做的呢?一切来自起源 SpringBoot 的启动类开始

  • @SpringBootApplication 标注的类就是 SpringBoot 项目的启动类
@SpringBootApplication
public class SpringIocApplication {public static void main(String[] args) {// 1. 获取Spring上下文对象(启动应用)ApplicationContext context = SpringApplication.run(SpringIocApplication.class, args);// 2. 从容器中获取Bean实例BeanLifeComponent beanLifeComponent = context.getBean(BeanLifeComponent.class);// 3. 使用BeanbeanLifeComponent.use();}
}

这个类和普通类唯一的区别就是 @SpringBootApplication 注解,这个注解也是 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

这是一个组合注解,里面包含了

  1. 元注解
  2. @SpringBootConfiguration
  3. EnableAutoConfiguration(开启自动配置)
  4. ComponentScan (包扫描)
1. 元注解

JDK 中提供了 4 个标准的用来对注解类型进行注解的注解类,我们称之为 meta-annotation(元注解),他们分别是:

  1. @Target:描述注解的使用范围(即被修饰的注解可以用在什么地方)
  2. Retention:描述注解保留的时间范围
  3. @Documented:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息
  4. Inherited:使被它修饰的注解具有继承性(如果每个类使用了被 @Inherited 修饰的注解,则其子类将自动具有该注解)
2. @SpringBootConfiguration

里面就是 @Configuration,标注当前类为配置类,其实只是做了一层封装,改了个名字而已

  • @Indexed 注解,是用来加速应用启动的,不用关心
@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Configuration  
@Indexed  
public @interface SpringBootConfiguration {  @AliasFor(  annotation = Configuration.class  )  boolean proxyBeanMethods() default true;  
}
3. @EnableAutoConfiguration

Spring 自动配置的核心注解,下面详细讲解

4. @ComponentScan
  • 可以通过 basePackageClassesbasePackages 来定义需要扫描的特定包
  • 如果没有定义特定的包,将从声明该注解的类的包开始扫描,这也是为什么 SpringBoot 项目声明的注解类必须要在启动类的目录下
  • excludeFilters 自定义过滤器,通常用于排除一些类,注解等

@EnableAutoConfiguration 详解

我们看其注解的实现:

@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 {};  
}

这个注解包含两部分:

  1. @Import({AutoConfigurationImportSelector.class})
  2. @AutoConfigurationPackage
@Import ({AutoConfigurationImportSelector. class})

使用 @Import 注解,导入了实现 ImportSelector 接口的实现类

public class AutoConfigurationImportSelector implements DeferredImportSelector, BeanClassLoaderAware, ResourceLoaderAware, BeanFactoryAware, EnvironmentAware, Ordered {  public String[] selectImports(AnnotationMetadata annotationMetadata) {  if (!this.isEnabled(annotationMetadata)) {  return NO_IMPORTS;  } else {  // 获取自动配置的配置类信息AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(annotationMetadata);  return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());  }  }
  • selectImport() 方法底层调用 getAutoConfigurationEntry() 方法,获取可自动配置的配置类信息集合

点进去:

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.<String>removeDuplicates(configurations);  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);  }  
}

getAutoConfigurationEntry() 方法通过调用 getCandidateConfigurations(annotationMetadata, attributes) 方法获取在配置文件中配置的所有自动配置类的集合

点进去:

//获取所有基于
// META-INF/spring/aot.factories文件
// META-INF/spring.factories
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {  ImportCandidates importCandidates = ImportCandidates.load(this.autoConfigurationAnnotation,  getBeanClassLoader());  List<String> configurations = importCandidates.getCandidates();  Assert.state(!CollectionUtils.isEmpty(configurations),  "No auto configuration classes found in " + "META-INF/spring/"  + this.autoConfigurationAnnotation.getName() + ".imports. If you "  + "are using a custom packaging, make sure that file is correct.");  return configurations;  
}
  • getCandidateConfigurations 方法的功能:
    • 获取所有基于 META-INF/spring/aot.factories 文件,META-INF/spring.factories 文件中配置类的集合

在引入的起步依赖中,通常都有包含以上两个文件image.png|342

  • 这里面包含了很多第三方依赖的配置文件(连续按两下 shift 可以查看对应的源码)
    1. 在加载自动配置类的时候,并不是将所有的配置全部加载进来,而是通过 @Conditional 等注解的判断进行动态加载。
      @ConditionalSpring 底层注解,意思就是根据不同的条件,来进行自己不同的条件判断,如果满足指定的条件,那么配置类里边的配置才会生效

    2. META-INF/spring/aot.factories 文件是 Spring 内部提供的一个约定俗成的加载方式,只需要在模块的 META-INF/spring/aot.factories 文件中配置即可,Spring 就会把响应的实现类注入到 Spring 容器中

:会加载所有 jar 包下的 classpath 路径下的 META-INF/spring/aot.factories 文件,这样文件不止一个

  • 比如 redis 的配置:RedisAutoConfigurationimage.png
  • 可以看到,配置文件中使用 @Bean 声明了一些对象,Spring 就会自动调用配置类中使用 @Bean 标识的方法,并把对象注册到 Spring IoC 容器中
  • 在加载自动配置类的时候,并不是将所有的配置全部加载进来,而是通过 @Conditional 等注解的判断进行动态加载
  • @ConditionalSpring 底层注解,意思就是会根据不同的条件,来进行自己不同的条件判断,如果满足指定的条件,那么配置类里面的配置才会生效
@AutoConfigurationPacket

源码如下:

@Target({ElementType.TYPE})  
@Retention(RetentionPolicy.RUNTIME)  
@Documented  
@Inherited  
@Import({AutoConfigurationPackages.Registrar.class})  
public @interface AutoConfigurationPackage {  String[] basePackages() default {};  Class<?>[] basePackageClasses() default {};  
}

这个注解主要是导入了一个配置文件 AutoConfigurationPackages.Registrar.class

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {  Registrar() {  }  public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {  AutoConfigurationPackages.register(registry, (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]));  }  public Set<Object> determineImports(AnnotationMetadata metadata) {  return Collections.singleton(new PackageImports(metadata));  }  
}
  • 这个类实现了 ImportBeanDefinitionRegistrar 类,就可以被注解 @Import 注解导入到 Spring 容器里
  • (String[])(new PackageImports(metadata)).getPackageNames().toArray(new String[0]):当前启动类所在的包名

所以:@AutoConfigurationPacket 就是将启动类所在的包下面的所有组件都扫描注册到 Spring 容器中

总结

SpringBoot 自动配置原理的大概流程如下:image.png
SpringBoot 程序启动时,会加载配置文件当中所定义的配置类,通过 @Import 注解将这些配置类全部加载到 SpringIoC 容器中,交给 IoC 容器管理

总结

  1. Bean 的作用域共分为 6 中:singletonprototyperequestsessionapplicationwebsocket
  2. Bean 的生命周期共分为 5 大部分:实例化、属性复制、初始化、使用和销毁
  3. SpringBoot 的自动配置原理源码口是:@SpringBootApplication 注解,这个注解封装了 3 个注解
    • @SpringBootConfiguration 标志当前类为配置类
    • @ComponentScan 进行包扫描(默认扫描的是启动类所在的当前包及其子包)
    • @EnableAutoConfiguration
      • @Import:读取当前项目下所有依赖 jar 包中 META-INF/spring.facctoriesMETA-INF/spring/aot.factories 两个文件里面定义的配置类(配置类中定义了 @Bean 注解标识的方法)
      • @AutoConfigurationPacket:把启动类所在包下面所有的组件都注入到 Spring 容器中
http://www.dtcms.com/a/314358.html

相关文章:

  • Java类与对象练习题
  • 运动想象 (MI) 分类学习系列 (18) : MSVTNet
  • 一(1)关于单链表中的疑问
  • Spring AI实战:SpringBoot项目结合Spring AI开发——提示词(Prompt)技术与工程实战详解
  • SAP-ABAP:ABAP Open SQL 深度解析:核心特性、性能优化与实践指南
  • 设计模式 -> 策略模式(Strategy Pattern)
  • 2025年8月4日私鱼创作平台v1.0.4公测版更新发布-完成大部分功能包含关注创作者以及发布作品及合集功能优雅草科技
  • 06 基于sklearn的机械学习-欠拟合、过拟合、正则化、逻辑回归
  • 线程互斥锁:守护临界区的关键
  • 可编辑190页PPT | 某科技集团数字化转型SAP解决方案
  • Vue 3 版本的 JWT 单点登录 (SSO) 实现
  • 国家科学技术奖答辩PPT案例_科技进步奖ppt制作_技术发明奖ppt设计美化_自然科学奖ppt模板 | WordinPPT
  • 使用mybatis生成器生成实体类mapper和查询参数文件,实现简单增删改查。使用log4j输出日志到控制台。使用配置文件注册Bean,配置视图解析器
  • 【Java】使用模板方法模式设计EasyExcel批量导入导出
  • Apache Camel 中 ProducerTemplate
  • 刷题日志(7)——二叉树高频习题(下)
  • 高精度实战:YOLOv11交叉口目标行为全透视——轨迹追踪×热力图×滞留分析(附完整代码)
  • FrePrompter: Frequency self-prompt for all-in-one image restoration
  • Opencv[一]
  • R 语言科研绘图第 67 期 --- 箱线图-显著性
  • Spark SQL:用SQL玩转大数据
  • OpenCV轻松入门_面向python(第二章图像处理基础)
  • 论文阅读笔记:《Dataset Distillation by Matching Training Trajectories》
  • 【数据结构初阶】--算法复杂度详解
  • 登录弹窗,cv直接使用
  • 【FreeRTOS】系统时钟配置
  • HTTP基本结构
  • ICCV 2025|单视频生成动态4D场景!中科大微软突破4D生成瓶颈,动画效果炸裂来袭!
  • ICCV 2025|可灵团队新作 ReCamMaster:从单视频到多视角生成,多角度看好莱坞大片
  • socket与udp