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

Spring Boot自动装配代码详解

  1. 概述

    • Spring Boot自动装配是其核心特性之一,它能够根据项目中添加的依赖自动配置Spring应用程序。通过自动装配,开发人员可以减少大量的配置工作,快速搭建起一个可用的Spring应用。
  2. 关键组件和注解

    • @SpringBootApplication注解
      • 这是Spring Boot应用的主注解,它是一个组合注解,实际上包含了@Configuration@EnableAutoConfiguration@ComponentScan三个注解。
      • @Configuration:表明这个类是一个配置类,用于定义Spring的Bean。在配置类中,可以通过@Bean注解方法来创建和配置Bean实例。例如:
        @Configuration
        public class AppConfig {@Beanpublic MyService myService() {return new MyServiceImpl();}
        }
        
        • 这里定义了一个名为myService的Bean,类型是MyService,其实现是MyServiceImpl
      • @EnableAutoConfiguration:这是自动装配的关键注解。它会启用Spring Boot的自动配置机制,告诉Spring Boot去根据项目的依赖和配置自动配置应用。它通过@Import注解导入了AutoConfigurationImportSelector类来实现自动配置的功能。
      • @ComponentScan:用于扫描指定包及其子包下的组件(如@Component@Service@Repository@Controller等注解标记的类),将它们注册为Spring的Bean。默认情况下,它会扫描主应用类所在的包及其子包。例如,如果主应用类在com.example.myapp包下,那么@ComponentScan会扫描com.example.myapp及其所有子包下的组件。
    • AutoConfigurationImportSelector
      • 这个类是自动装配的核心实现类。它实现了ImportSelector接口,该接口的selectImports方法用于返回要导入的配置类的全限定名数组。
      • AutoConfigurationImportSelector中,selectImports方法会从META - INF/spring.factories文件中读取自动配置类的列表。它通过SpringFactoriesLoader.loadFactoryNames方法来加载这些配置类,例如:
        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());
        }
        
      • 这里的getAutoConfigurationEntry方法会获取需要自动导入的配置类,这些配置类是根据项目中的依赖和条件来确定的。
  3. META - INF/spring.factories文件机制

    • 这是自动装配的重要配置文件。在Spring Boot的各个依赖中,都可以包含META - INF/spring.factories文件。
    • 这个文件的格式是key = value的形式,其中一个关键的配置项是org.springframework.boot.autoconfigure.EnableAutoConfiguration。它的值是一个自动配置类的列表,例如:
      org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\// 其他自动配置类
      
    • 当Spring Boot启动时,AutoConfigurationImportSelector会读取这些文件,找到所有的自动配置类。然后,根据条件注解(如@ConditionalOnClass@ConditionalOnMissingBean等)来判断这些自动配置类是否应该被应用。
    • 条件注解示例
      • @ConditionalOnClass:这个注解用于判断某个类是否在类路径上。例如,DataSourceAutoConfiguration中有如下注解:
        @Configuration
        @ConditionalOnClass({DataSource.class, EmbeddedDatabaseType.class})
        public class DataSourceAutoConfiguration {// 配置内容
        }
        
        • 这表示只有当DataSource类和EmbeddedDatabaseType类都在类路径上时,DataSourceAutoConfiguration这个自动配置类才会被应用。这样可以确保只有在项目中添加了相关的数据源依赖时,才会进行数据源的自动配置。
      • @ConditionalOnMissingBean:用于判断某个类型的Bean是否不存在。例如,在某个自动配置类中定义一个方法来配置一个Bean:
        @Bean
        @ConditionalOnMissingBean
        public MyBean myBean() {return new MyBeanImpl();
        }
        
        • 这表示只有当容器中不存在MyBean类型的Bean时,才会创建并添加MyBeanImpl这个Bean到容器中。
  4. 自动配置的过程

    • Spring Boot应用启动时,首先会加载主应用类,由于@SpringBootApplication注解的存在,@Configuration注解使得这个类被视为一个配置类,@ComponentScan开始扫描组件。
    • 同时,@EnableAutoConfiguration触发自动装配过程。AutoConfigurationImportSelector从各个依赖的META - INF/spring.factories文件中获取自动配置类列表。
    • 然后,对于每个自动配置类,根据条件注解来检查是否满足应用条件。如果满足条件,就会将这个自动配置类加载到Spring容器中,自动配置类中的@Bean方法会被调用,创建和配置相应的Bean,从而完成自动装配的过程。

具体源码讲解

  1. @SpringBootApplication注解源码分析

    • 首先查看@SpringBootApplication注解的定义:
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoExcludeFilter.class)
    })
    public class SpringBootApplication {
    }
    
    • 可以看到它是一个组合注解,包含了@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan
    • @SpringBootConfiguration:它实际上就是@Configuration注解,用于标识这个类是一个配置类。
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Configuration
    public class SpringBootConfiguration {
    }
    
    • @EnableAutoConfiguration:这是自动装配的关键。它的源码如下:
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @AutoConfigurationPackage
    @Import(AutoConfigurationImportSelector.class)
    public class EnableAutoConfiguration {
    }
    
    • 其中@Import(AutoConfigurationImportSelector.class)是核心部分。这个AutoConfigurationImportSelector类用于加载自动配置类。
    • @ComponentScan:用于扫描组件,它有一些默认的扫描规则和可以自定义的过滤规则,如上述代码中的excludeFilters,用于排除某些类型的组件扫描。
  2. AutoConfigurationImportSelector源码分析

    • AutoConfigurationImportSelector实现了ImportSelector接口,其中关键的方法是selectImports
    @Override
    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());
    }
    
    • 这个方法首先检查自动配置是否启用。然后通过AutoConfigurationMetadataLoader.loadMetadata加载自动配置元数据,再通过getAutoConfigurationEntry获取自动配置项。
    • 深入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;
    }
    
    • SpringFactoriesLoader.loadFactoryNames方法会读取META - INF/spring.factories文件,查找org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置类列表。
  3. META - INF/spring.factories文件读取源码分析

    • SpringFactoriesLoader类用于读取spring.factories文件,关键方法是loadFactoryNames
    public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {String factoryTypeName = factoryType.getName();return loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList());
    }
    
    • 它调用了loadSpringFactories方法:
    private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {MultiValueMap<String, String> result = cache.get(classLoader);if (result!= null) {return result;}try {Enumeration<URL> urls = (classLoader!= null?classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));result = new LinkedMultiValueMap<>();while (urls.hasMoreElements()) {URL url = urls.nextElement();UrlResource resource = new UrlResource(url);Properties properties = PropertiesLoaderUtils.loadProperties(resource);for (Map.Entry<Object, Object> entry : properties.entrySet()) {String factoryTypeName = ((String) entry.getKey()).trim();for (String factoryImplementationName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {result.add(factoryTypeName, factoryImplementationName.trim());}}}cache.put(classLoader, result);return result;} catch (IOException ex) {throw new IllegalArgumentException("Unable to load factories from location [" +FACTORIES_RESOURCE_LOCATION + "]", ex);}
    }
    
    • 这个方法首先检查缓存中是否已经有读取的结果。如果没有,就通过ClassLoader获取META - INF/spring.factories文件的URL,然后将其内容读取到Properties对象中。最后,将文件中的配置解析出来,以key - value的形式存储在MultiValueMap中,其中key是配置项的类型(如org.springframework.boot.autoconfigure.EnableAutoConfiguration),value是对应的配置类列表。
  4. 条件注解的源码体现(以@ConditionalOnClass为例)

    • @ConditionalOnClass注解用于判断某个类是否在类路径上。它的实现基于Condition接口。
    • 当Spring容器在处理自动配置类时,会检查条件注解。@ConditionalOnClass对应的Condition实现类是OnClassCondition。在自动配置类加载过程中,会调用OnClassConditionmatches方法来判断条件是否满足:
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {// 省略部分代码List<String> onClasses = getCandidates(metadata, ConditionalOnClass.class);if (onClasses!= null) {List<String> missing = filter(onClasses, ClassNameFilter.MISSING, context);if (!missing.isEmpty()) {return false;}}List<String> onMissingClasses = getCandidates(metadata, ConditionalOnMissingClass.class);if (onMissingClasses!= null) {List<String> present = filter(onMissingClasses, ClassNameFilter.PRESENT, context);if (!present.isEmpty()) {return false;}}return true;
    }
    
    • 这个方法会获取@ConditionalOnClass注解中指定的类列表,然后检查这些类是否在类路径上。如果有任何一个指定的类不存在,就返回false,表示条件不满足,自动配置类不会被加载。通过这样的机制,Spring Boot可以根据类的存在与否来决定自动配置类的加载与否,实现智能的自动装配。

相关文章:

Spring Boot自动装配代码详解

概述 Spring Boot自动装配是其核心特性之一&#xff0c;它能够根据项目中添加的依赖自动配置Spring应用程序。通过自动装配&#xff0c;开发人员可以减少大量的配置工作&#xff0c;快速搭建起一个可用的Spring应用。 关键组件和注解 SpringBootApplication注解 这是Spring Bo…...

渗透测试-非寻常漏洞案例

声明 本文章所分享内容仅用于网络安全技术讨论&#xff0c;切勿用于违法途径&#xff0c;所有渗透都需获取授权&#xff0c;违者后果自行承担&#xff0c;与本号及作者无关&#xff0c;请谨记守法. 此文章不允许未经授权转发至除先知社区以外的其它平台&#xff01;&#xff0…...

122. 买卖股票的最佳时机 II

https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/?envTypestudy-plan-v2&envIdtop-interview-150问题分析&#xff1a; 和买卖股票的最佳时机I这题相比&#xff0c;区别就是可以买多只股票虽然同时只能持有一支&#xff0c;但是我们还是可以…...

Python爬虫入门指南:从零开始抓取数据

Python爬虫入门指南&#xff1a;从零开始抓取数据 引言 在大数据时代&#xff0c;数据是新的石油。而爬虫作为获取数据的重要手段&#xff0c;受到了越来越多的关注。Python作为一门强大的编程语言&#xff0c;其简洁易用的特性使得它成为爬虫开发的首选语言。本篇文章将带你…...

Android使用JAVA调用JNI原生C++方法

1.native-lib.cpp为要生成so库的源码文件 2.JNI函数声明说明 NewStringUTF函数会返回jstring JNI函数声明规则 3.JAVA中声明及调用JNI函数 声明&#xff1a; 调用 4.源码地址&#xff1a; gitgithub.com:tonyimax/UpdateTimeByThread.git...

ros常用命令记录

文章目录 1.基本2.rosbag2.1录制rosbag包2.2播放录制的ROS包 3.生命周期4.ROS启动&#xff0c;roslaunch5.ROS消息发布6.ROS消息后台打印监控 1.基本 ros2 topic list #查看话题列表2.rosbag 2.1录制rosbag包 ros2 bag record <topic_name> #记录单个主题消息 ros2 ba…...

UE5材质节点VertexNormalWs/PixelNormalWS

VertexNormalWs顶点法线方向&#xff0c;此节点可以做物体上积雪、青苔等效果 PixelNormalWS像素法线方向...

友元和运算符重载

1. 友元 可以把某些选定的函数看作类的“荣誉函数”&#xff0c;允许它们访问类对象中非公共的成员&#xff0c;就好像它们是类的成员一样&#xff0c;这种函数称为类的友元。友元可以访问类对象的任意成员。 1.1 友元函数 友元函数是一种定义在类外部的普通函数&#xff0…...

【数据库事务锁的类型:读锁/写锁、悲观锁/乐观锁、表锁/页锁/行锁】

数据库事务锁的类型&#xff1a;读锁/写锁、悲观锁/乐观锁、表锁/页锁/行锁 一、读锁/写锁1、锁定读 二、悲观锁/乐观锁2.1 悲观锁2.2 乐观锁 三、表锁/页锁/行锁3.1 表级别的S锁、X锁3.2 表级别的意向锁&#xff08;intention lock&#xff09; 一、读锁/写锁 对于数据库中并…...

【Motion Builder】配置c++插件开发环境

目录 准备环境构建官方案例另行构建经验分享附录 准备环境 安装Motion Builder 2024并破解安装Qt 5.15.2 截止至2024年12月19日&#xff0c;Qt的在线安装器的默认页面是没有5.15.2版本的。你需要&#xff1a;在“选择组件”界面&#xff0c;选择“Archive”&#xff0c;点击“…...

多线程访问FFmpegFrameGrabber.start方法阻塞问题

一、背景 项目集成网络摄像头实现直播功能需要用到ffmpeg处理rtmp视频流进行web端播放 通过网上资源找到大神的springboot项目实现了rtmp视频流转为http请求进行视频中转功能&#xff0c;其底层利用javacv的FFmpegFrameGrabber进行拉流、推流&#xff0c;进而实现了视频中转。 …...

MySQL使用记录

char和varchar varchar是可变长的&#xff0c;实际用多少它就占多少&#xff0c;和char不同&#xff0c;char规定多少它就会占多少 varchar的长度是字符个数&#xff0c;不管是数字、英文还是汉字&#xff0c;varchar(10)都可以存10个&#xff0c;而不会出现因为汉字占更多的字…...

【视觉SLAM:六、视觉里程计Ⅰ:特征点法】

视觉里程计&#xff08;Visual Odometry, VO&#xff09;是通过处理图像序列&#xff0c;估计摄像头在时间上的相对位姿变化的技术。它是视觉SLAM的重要组成部分之一&#xff0c;主要通过提取图像中的信息&#xff08;如特征点或直接像素强度&#xff09;来实现相机运动估计。以…...

Python 数据结构揭秘:栈与队列

栈&#xff08;Stack&#xff09; 定义 栈是一种后进先出&#xff08;Last In First Out, LIFO&#xff09;的数据结构。它类似于一个容器&#xff0c;只能在一端进行插入和删除操作。栈有两个主要的操作&#xff1a;push&#xff08;入栈&#xff09;和 pop&#xff08;出栈…...

常见的框架漏洞

1.Thinkphp Thinkphp5x远程命令执行及getshell 搭建靶场 cd vulhub/thinkphp/5-rce docker-compose up -d 首页 漏洞根本源于 thinkphp/library/think/Request.php 中method方法可以进行变量覆盖&#xff0c;通过覆盖类的核心属性filter导致rce&#xff0c;其攻击点较为多&…...

在C++中实现一个能够捕获弹窗、检查内容并在满足条件时点击按钮的程序;使用python的方案

在C中实现一个能够捕获弹窗、检查内容并在满足条件时点击按钮的程序是相当复杂的&#xff0c;因为C本身并不直接提供高级的GUI自动化功能。通常&#xff0c;这样的任务会使用Windows API&#xff08;如User32.dll中的函数&#xff09;或者一些第三方库&#xff08;如UIAutomati…...

《Vue3实战教程》26:Vue3Transition

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》...

【架构设计(一)】常见的Java架构模式

常见的 Java 架构模式解析 在 Java 开发领域&#xff0c;选择合适的架构模式对于构建高效、可维护且能满足业务需求的软件系统至关重要。本文将深入探讨几种常见的 Java架构模式&#xff0c;包括单体架构与微服务架构、分层架构与微服务架构的对比&#xff0c;以及事件驱动架构…...

自定义有序Map

package cn.ziqirj.common.utils;import lombok.Getter; import lombok.Setter;import java.util.ArrayList; import java.util.List;/*** 模拟Map集合&#xff0c;key不可重复&#xff0c;按插入顺序排序* author zhangji** param <T>*/ public class CustomOrderlyMap&…...

Jenkins(持续集成与自动化部署)

Jenkins 是一个开源软件项目&#xff0c;是基于Java开发的一种持续集成工具。 官网&#xff1a;https://www.jenkins.io/ GitLab安装使用 安装前提&#xff1a;内存至少需要4G 官方网站&#xff1a;https://about.gitlab.com/ 安装文档&#xff1a;https://docs.gitlab.c…...

转转集团旗下首家二手多品类循环仓店“超级转转”开业

6月9日&#xff0c;国内领先的循环经济企业转转集团旗下首家二手多品类循环仓店“超级转转”正式开业。 转转集团创始人兼CEO黄炜、转转循环时尚发起人朱珠、转转集团COO兼红布林CEO胡伟琨、王府井集团副总裁祝捷等出席了开业剪彩仪式。 据「TMT星球」了解&#xff0c;“超级…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)

文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...

在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?

uni-app 中 Web-view 与 Vue 页面的通讯机制详解 一、Web-view 简介 Web-view 是 uni-app 提供的一个重要组件&#xff0c;用于在原生应用中加载 HTML 页面&#xff1a; 支持加载本地 HTML 文件支持加载远程 HTML 页面实现 Web 与原生的双向通讯可用于嵌入第三方网页或 H5 应…...

纯 Java 项目(非 SpringBoot)集成 Mybatis-Plus 和 Mybatis-Plus-Join

纯 Java 项目&#xff08;非 SpringBoot&#xff09;集成 Mybatis-Plus 和 Mybatis-Plus-Join 1、依赖1.1、依赖版本1.2、pom.xml 2、代码2.1、SqlSession 构造器2.2、MybatisPlus代码生成器2.3、获取 config.yml 配置2.3.1、config.yml2.3.2、项目配置类 2.4、ftl 模板2.4.1、…...

第7篇:中间件全链路监控与 SQL 性能分析实践

7.1 章节导读 在构建数据库中间件的过程中&#xff0c;可观测性 和 性能分析 是保障系统稳定性与可维护性的核心能力。 特别是在复杂分布式场景中&#xff0c;必须做到&#xff1a; &#x1f50d; 追踪每一条 SQL 的生命周期&#xff08;从入口到数据库执行&#xff09;&#…...

windows系统MySQL安装文档

概览&#xff1a;本文讨论了MySQL的安装、使用过程中涉及的解压、配置、初始化、注册服务、启动、修改密码、登录、退出以及卸载等相关内容&#xff0c;为学习者提供全面的操作指导。关键要点包括&#xff1a; 解压 &#xff1a;下载完成后解压压缩包&#xff0c;得到MySQL 8.…...

WPF八大法则:告别模态窗口卡顿

⚙️ 核心问题&#xff1a;阻塞式模态窗口的缺陷 原始代码中ShowDialog()会阻塞UI线程&#xff0c;导致后续逻辑无法执行&#xff1a; var result modalWindow.ShowDialog(); // 线程阻塞 ProcessResult(result); // 必须等待窗口关闭根本问题&#xff1a…...

[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG

TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码&#xff1a;HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...

0x-3-Oracle 23 ai-sqlcl 25.1 集成安装-配置和优化

是不是受够了安装了oracle database之后sqlplus的简陋&#xff0c;无法删除无法上下翻页的苦恼。 可以安装readline和rlwrap插件的话&#xff0c;配置.bahs_profile后也能解决上下翻页这些&#xff0c;但是很多生产环境无法安装rpm包。 oracle提供了sqlcl免费许可&#xff0c…...