@SpringBootApplication自动配置原理剖析

news2024/9/27 23:25:26

@SpringBootApplication自动配置原理剖析

自动配置: 根据我们添加的依赖,会自动将一些配置类的bean注册进ioc容器中,可以使用@Autowired或者@Resource等注解来使用它。

1.1 SpringBootApplication

Spring Boot项目创建完成会默认生成一个Application的入口类(启动类),命名规则artifactId(项目名)+Application
在这里插入图片描述

@SpringBootConfiguration //标明该类为配置类
@EnableAutoConfiguration //启动自动配置功能
@ComponentScan( //启动包扫描 
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)

@SpringBootApplication是一个"三体"结构,实际上它是一个复合Annotation(注解):

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.context.TypeExcludeFilter;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.core.annotation.AliasFor;

//这个注解表示 @SpringBootApplication 只能用于类级别的元素(即 ElementType.TYPE)。
@Target({ElementType.TYPE}) //注解的适用范围,Type表示注解可以描述在类,接口,注解或枚举中

//这个注解表示 @SpringBootApplication 在运行时仍然有效,因此可以通过反射机制访问到。
@Retention(RetentionPolicy.RUNTIME) //表示注解的生命周期,Runtime运行时

//这个注解表示 @SpringBootApplication 的相关信息会被包含在 Java 文档中。
@Documented 

//这个注解表示如果一个父类被 @SpringBootApplication 注解,那么它的子类也会继承这个注解。
@Inherited 

//这个注解等同于 @Configuration 注解,表示这是一个配置类,可以被用来声明 Bean 对象并装配到 Spring 容器中。在这个上下文中,它指示当前类是一个 Spring 配置类。
@SpringBootConfiguration //标明该类为配置类

//这个注解是 Spring Boot 自动配置的核心。当应用启动时,Spring Boot 会根据 classpath 中存在的库(JAR 文件)来自动配置 Bean。
@EnableAutoConfiguration //启动自动配置功能

//这个注解用于启用组件扫描,以便发现和管理带有特定注解的类(如 @Component、@Service、@Repository 和 @Controller 等)。如果没有指定扫描的包路径,那么默认会扫描包含 @SpringBootApplication 注解的类所在的包及其子包。
@ComponentScan( //启动包扫描 
    excludeFilters = {@Filter(
    type = FilterType.CUSTOM,
    classes = {TypeExcludeFilter.class}
), @Filter(
    type = FilterType.CUSTOM,
    classes = {AutoConfigurationExcludeFilter.class}
)}
)
//通过使用 @SpringBootApplication 注解,开发者可以在单一的类中定义整个应用程序所需的配置,而不需要在 XML 或 Java 配置文件中进行大量的手动配置。这正是 Spring Boot 的核心理念之一:约定优于配置。
public @interface SpringBootApplication {

    //根据class来排除特定的自动配置类,使其不能加入spring容器,传入参数value类型是class类型
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    //这个方法是 @EnableAutoConfiguration 注解的一个别名,用于指定要排除的自动配置类。
    Class<?>[] exclude() default {};

    //根据classname 来排除特定的类,使其不能加入spring容器,传入参数value类型是class的全类名字符串数组
    @AliasFor(
        annotation = EnableAutoConfiguration.class
    )
    //这个方法也是 @EnableAutoConfiguration 注解的一个别名,用于指定要排除的自动配置类的名称。
    String[] excludeName() default {};

    //指定扫描包,参数是包名的字符串数组,用于激活@Component(元件)等注解类的初始化
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackages"
    )
    //这个方法是 @ComponentScan 注解的一个别名,用于指定要扫描的基础包。
    String[] scanBasePackages() default {};

    //扫描特定的包,参数类是Class类型数组
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "basePackageClasses"
    )
    //这个方法也是 @ComponentScan 注解的一个别名,用于指定要扫描的基础包中的类。
    Class<?>[] scanBasePackageClasses() default {};

    //bean名称生成器,用于命名被扫描到并注册成spring容器中的bean的bean名称
    @AliasFor(
        annotation = ComponentScan.class,
        attribute = "nameGenerator"
    )
    //这个方法是 @ComponentScan 注解的一个别名,用于指定 Bean 名称生成器。
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    /**
     * 注解的意思是proxyBeanMethods配置类是用来指定 @Bean 注解标注的方法是否使用代理,默认是 true 使用代理
     * (proxyBeanMethods = true)[保证每个@Bean方法被调用多少次返回的组件都是新创建的]
     */
    @AliasFor(
        annotation = Configuration.class
    )
    //这个方法是 @Configuration 注解的一个别名,用于指定是否代理 bean 方法。默认为 true,表示会代理。
    boolean proxyBeanMethods() default true;
}

@AliasFor注解,该注解通常用于桥接到其他注解,该注解的属性中指定了所桥接的注解类,@SpringBootApplication定义的属性在"三体"组合注解中已经定义过了,之所以使用@AliasFor注解并重新在@SpringBootApplication中进行定义,更多的是为了减少用户使用多注解带来的麻烦

Full全模式,Lite轻量级模式
 boolean proxyBeanMethods() default true;
  • Full(proxyBeanMethods = true): proxyBeanMethods参数设置为true时即为:Full全模式。该模式下注入容器中的同一个组件无论被取出多少次都是同一个bean实例,即单实例对象,在该模式下Spring Boot每次启动都会判断检查容器中是否存在该组件。
  • Lite(proxyBeanMethods = false) proxyBeanMethods参数设置为false时即为:Lite轻量级模式。该模式下注入容器中的同一个组件无论被取出多少次都是不同的bean实例,即多实例对象,在该模式下Spring Boot每次启动会跳过检查容器中是否存在该组件。

什么时候用Full全模式,什么时候用Lite轻量级模式?

  • 当在你的同一个Configuration配置类中,注入到容器中的bean实例之间有依赖关系时,建议使用Full全模式
  • 当在你的同一个Configuration配置类中,注入到容器中的bean实例之间没有依赖关系时,建议使用Lite轻量级模式,以提高Spring Boot的启动速度和性能

1.2 @ComponentScan

@ComponentScan 注解用于启动组件扫描,以便发现和管理带有特定注解的类(如 @Component@Service@Repository@Controller 等)。在这个注解中使用了两个 @Filter,它们的作用是排除某些类或包从组件扫描中。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.core.annotation.AliasFor;

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;

    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;

    String resourcePattern() default "**/*.class";

    boolean useDefaultFilters() default true;

    ComponentScan.Filter[] includeFilters() default {};

    ComponentScan.Filter[] excludeFilters() default {};

    boolean lazyInit() default false;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public @interface Filter {
        FilterType type() default FilterType.ANNOTATION;

        @AliasFor("classes")
        Class<?>[] value() default {};

        @AliasFor("value")
        Class<?>[] classes() default {};

        String[] pattern() default {};
    }
}

  • 1.TypeExcludeFilter
    这是一个 Spring Boot 内置的过滤器,它会排除所有以 .package-info 结尾的文件。这些文件通常包含一些包级别的 Javadoc 注释信息,而不是实际的类定义。因此,将它们排除在组件扫描之外可以提高扫描效率。

  • 2.AutoConfigurationExcludeFilter
    这个过滤器是 Spring Boot 自动配置的一部分,它会排除那些已经被自动配置处理过的类。因为自动配置已经为这些类创建了相应的 Bean,所以没有必要再通过组件扫描来发现它们。

综上所述,这段代码的意思是:在进行组件扫描时,除了排除以 .package-info 结尾的文件外,还排除那些已经被自动配置处理过的类。这样做的目的是避免重复地创建相同的 Bean,从而优化应用程序的启动速度和运行性能。

1.3 EnableAutoConfiguration

@EnableAutoConfiguration 是 Spring Boot 中的一个核心注解,用于启用自动配置功能。让我们从源码的角度来解释这个注解的工作原理:
1.定义:
@EnableAutoConfiguration 注解是通过在 Java 类上使用来启用自动配置的。它的定义如下:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.boot.autoconfigure;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;

@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. 组合注解
    @EnableAutoConfiguration 本身是一个复合注解,它包含两个嵌套注解:

    • @AutoConfigurationPackage:这个注解用于创建一个特殊的 Bean,该 Bean 可以确定主配置包的位置,并将所有扫描的基础包添加到同一个逻辑容器中。
    • @Import(AutoConfigurationImportSelector.class):这个注解告诉 Spring 容器要导入一个名为 AutoConfigurationImportSelector 的类。这个类是自动配置的核心实现,负责根据 classpath 中存在的库来决定哪些自动配置类应该被激活。
  2. 自动配置过程
    当你在一个类上使用 @EnableAutoConfiguration 注解时,Spring 容器会读取该注解并执行以下步骤:

    a. 创建一个 AutoConfigurationImportSelector 实例。
    b. 调用 AutoConfigurationImportSelector.selectImports() 方法,该方法会遍历 classpath 中的 META-INF/spring.factories 文件,并查找与 org.springframework.boot.autoconfigure.EnableAutoConfiguration 关联的所有条目。
    c. 对于每个找到的自动配置类,检查是否满足 @Conditional 注解所指定的条件。如果满足条件,则将该自动配置类添加到待导入的列表中。
    d. 将列表中的所有自动配置类注入到 Spring 容器中,这些类通常会定义一些额外的 Bean 来提供所需的功能。

  3. 自定义排除
    @EnableAutoConfiguration 注解允许通过 excludeexcludeName 属性来排除特定的自动配置类。这两个属性分别对应了类名和类的全限定名。

总结起来,@EnableAutoConfiguration 注解通过组合其他注解和利用 AutoConfigurationImportSelector 类实现了 Spring Boot 自动配置的核心功能。它会根据 classpath 中存在的库自动配置所需的 Bean,从而简化应用程序的配置工作。

1.4 逐行解释getAutoConfigurationEntry方法

这段代码是 AutoConfigurationImportSelector 类的 getAutoConfigurationEntry 方法的实现。这个方法负责处理 @EnableAutoConfiguration 注解并确定要导入的自动配置类列表。让我们逐行解释:


 protected AutoConfigurationImportSelector.AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
    //这一行检查 @EnableAutoConfiguration 注解是否启用。如果注解被禁用,则直接返回一个空的 AutoConfigurationEntry 对象。
        if (!this.isEnabled(annotationMetadata)) {
            return EMPTY_ENTRY;
        } else {
            //这一行从 annotationMetadata 中获取 @EnableAutoConfiguration 注解的所有属性,并将它们封装为一个 AnnotationAttributes 对象。
            AnnotationAttributes attributes = this.getAttributes(annotationMetadata);

            //这一行从 META-INF/spring.factories 文件中获取所有与 org.springframework.boot.autoconfigure.EnableAutoConfiguration 关联的条目,这些条目表示了可能需要导入的自动配置类列表。
            List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);

            //这一行移除 configurations 列表中的重复项。
            configurations = this.removeDuplicates(configurations);

            //这一行从 @EnableAutoConfiguration 注解的 exclude 和 excludeName 属性中获取排除的自动配置类列表。
            Set<String> exclusions = this.getExclusions(annotationMetadata, attributes);

            //这一行检查 exclusions 列表中的类是否存在于 configurations 列表中,如果不包含则抛出异常。
            this.checkExcludedClasses(configurations, exclusions);

            //这一行从 configurations 列表中移除所有出现在 exclusions 列表中的类。
            configurations.removeAll(exclusions);

            //这一行使用 getConfigurationClassFilter() 方法获取一个过滤器,该过滤器用于进一步筛选 configurations 列表中的类。
            configurations = this.getConfigurationClassFilter().filter(configurations);

            //这一行触发一个事件,通知其他监听者有关自动配置导入的信息。
            this.fireAutoConfigurationImportEvents(configurations, exclusions);
            
            //最后,返回一个新的 AutoConfigurationImportSelector.AutoConfigurationEntry 对象,其中包含了待导入的自动配置类列表和排除的自动配置类列表。
            return new AutoConfigurationImportSelector.AutoConfigurationEntry(configurations, exclusions);
        }
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1310016.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

推荐一些跨平台的比较优秀的翻译服务(软件或平台)

因为编程及查阅资料需要频繁的查阅英文&#xff0c;推荐一些跨平台的比较优秀的翻译服务&#xff08;软件或平台&#xff09; 1、DeepL Translate (https://www.deepl.com/translator) 这是一款基于机器翻译的在线翻译软件。win、安卓、Linux、IOS上都有可用的版本也可以基于w…

Android12编译kernel4.9解决:scripts/gcc-wrapper.py, line 79, in run_gcc(一百六十八)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a;多媒…

《数据结构、算法与应用C++语言描述》-最大高度优先左高树-C++实现

左高树 完整可编译运行代码见&#xff1a;Github::Data-Structures-Algorithms-and-Applications/_26maxHblt 定义 (大顶堆和小顶堆)堆结构是一种隐式数据结构(implicit data structure)。用完全二叉树表示的堆在数组中是隐式存储的(即没有明确的指针或其他数据能够用来重塑…

从池化的角度看GNN(包含PR-GNN,EdgePool等7篇论文)上篇

从池化的角度看GNN&#xff08;包含PR-GNN&#xff0c;EdgePool等7篇论文&#xff09; 前言一些总结一些早期论文的简要介绍1️⃣论文PR-GNN&#xff1a;《Pooling Regularized Graph Neural Network for fMRI Biomarker Analysis》 下一篇章笔记链接 前言 这里是早期的笔记&a…

MySQL 系列:注意 ORDER 和 LIMIT 联合使用的陷阱

文章目录 前言背后的原因ORDER BY 排序列存在相同值时返回顺序是不固定的LIMIT 和 ORDER BY 联合使用时的行为ORDER BY 或 GROUP BY 和 LIMIT 联合使用优化器默认使用有序索引 如何解决其它说明个人简介 前言 不知道大家在在分页查询中有没有遇到过这个问题&#xff0c;分页查…

pytorch之优化器、学习率函数学习

1、TORCH.OPTIM torch.optim是一个实现各种优化算法的包。大多数常用的方法都已经支持&#xff0c;并且接口足够通用&#xff0c;因此将来也可以轻松集成更复杂的方法 1、如何使用优化器 要使用&#xff0c;torch.optim您必须构造一个优化器对象&#xff0c;该对象将保存当前…

立创EDA把三个单独的PCB合并成一个文件

[TOC](立创EDA把三个单独的PCB合并成一个文件 1.具体操作 1.具体操作 参考&#xff1a;立创社区 先选中PCB CTRLSHIFTC, CTRLSHIFTV** **

uniapp交互反馈api的使用示例

官方文档链接&#xff1a;uni.showToast(OBJECT) | uni-app官网 1.uni.showToast({}) 显示消息提示框。 常用属性&#xff1a; title:页面提示的内容 image&#xff1a;改变提示框默认的icon图标 duration&#xff1a;提示框在页面显示多少秒才让它消失 添加了image属性后。 注…

PHP之添加文字水印,两端文字分别设置不同的样式,支持透明度

/*** 给图片添加文字水印 可控制字体颜色透明度&#xff0c;默认是居中* param string $imagePath 图片地址* param string $outputPath 新图片地址 默认使用$imgurl* param string $textArray 水印文字* param int $fontSize 字体大小* param string $fontPath 字体文件路径* …

Python爬虫实战-采集微博评论,看看大家都在讨论什么

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 开发环境: python 3.8: 解释器 pycharm: 代码编辑器 模块使用: requests: 发送请求 parsel: 解析数据 jieba pandas stylecloud 如何安装python第三方模块: win R 输入 cmd 点击确定, 输入安装命令 pip install 模块名…

PLC-Recorder V3版本软件升级方法

PLC-Recorder V3软件进行了架构优化&#xff0c;包括采集服务器、客户端、授权管理等组件。升级方法与V2版本相似&#xff0c;但是也有一些变化&#xff0c;说明如下&#xff1a; 一、从V2向V3版本升级 1、退出原PLCRecorder&#xff1a;关闭右下角的图标。 2、退出打开的离线…

前端接入若依后,页面白屏问题排查

白屏问题分析 页面停留一段时间后&#xff0c;通过tab打开其他的页面&#xff0c;界面会白屏或者无法跳转&#xff1b; 白屏的时候控制台无任何报错无法跳转的时候&#xff0c;控制台会输出错误信息&#xff0c;见截图 1. 无报错白屏问题 通过查找若依的issues找到一个问题点…

C# WPF上位机开发(动态添加控件)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 写图形界面软件的时候&#xff0c;我们经常会遇到一种情况。那就是图形界面上面&#xff0c;显示的控件可能是不定的。有可能多&#xff0c;也有可…

外汇天眼:Coinbase国际交易所将启动现货市场

Coinbase宣布了Coinbase国际交易所扩张的下一阶段——退出符合条件客户的非美国现货市场。 这一最新发展旨在满足Coinbase全球用户群体的独特需求和需求&#xff0c;同时强化其扩大国际访问可信产品和服务的战略使命。 Coinbase国际交易所现货交易的推出和扩展将分阶段进行。1…

vue3+vite4中使用svg,使用iconfont-svg图标

记录一下vue3中如何使用svg图标&#xff0c;vue2中大家常用iconfont字体图标&#xff0c;现在vue3大家都又推荐svg的方式使用图表&#xff0c;包括elementplus组件库也变成使用svg方式引用图标。 1、创建svg组件 components/IconSvg.vue <template><svg class"…

avue-form 附件上传增加参数;上传前检查是否重复 覆盖或者跳过

效果 html: <el-dialog title"设备台账导入" append-to-body :visible.sync"excelBox" width"555px"><avue-form :option"excelOption" v-model"excelForm" :upload-after"uploadAfter" :upload-before…

Axure元件库使用与ProcessOn流程图

Axure元件库 自定义Axure元件库&#xff1a; 打开Axure RP软件&#xff0c;并点击菜单栏中的“元件库”选项&#xff0c;选择“新建元件库”。 在弹出的对话框中&#xff0c;选择一个文件夹来保存您的自定义元件库&#xff0c;并给它一个名称。 在Axure RP的主界面上&#x…

不需要联网的ocr项目

地址 GitHub - plantree/ocr-pwa: A simple PWA for OCR, based on Tesseract. 协议 mit 界面 推荐理由 可以离线使用&#xff0c;隐私安全

HDPE硅芯管强度高,抗压抗张和抗冲击强,外层不需其它套管

HDPE硅芯管是一种高性能的管道材料&#xff0c;具有强度高、抗压抗张和抗冲击强的特点。这种管道材料采用高密度聚乙烯&#xff08;HDPE&#xff09;作为基础材料&#xff0c;并添加了硅质增强剂&#xff0c;使得管道具有优异的力学性能和耐久性。 HDPE硅芯管的强度高&#xf…

【VS Code开发】使用Live Server搭建MENJA小游戏并发布至公网远程访问

文章目录 前言1. 编写MENJA小游戏2. 安装cpolar内网穿透3. 配置MENJA小游戏公网访问地址4. 实现公网访问MENJA小游戏5. 固定MENJA小游戏公网地址 前言 本篇教程&#xff0c;我们将通过VS Code实现远程开发MENJA小游戏&#xff0c;并通过cpolar内网穿透发布到公网&#xff0c;分…