【Java Web 快速入门】十一、Spring Boot 原理

目录

  • Spring Boot 原理
    • 配置优先级
    • Bean 管理
      • 获取 Bean
      • Bean 的作用域
      • 第三方 Bean
    • Spring Boot 底层原理
      • 起步依赖
      • 自动配置
        • 核心原理
        • 实例说明
          • 例 1:自定义一个 “日志 starter”
          • 例 2:SpringBoot 自带的 spring-boot-starter-web
        • 关键总结

Spring Boot 原理

配置优先级

Spring Boot 中支持三种格式的配置文件:

  • application.properties

    server.port=8081
    
  • application.yml

    server:port: 8082
    
  • application.yaml

    server:port: 8083
    

在代码中配置这三个文件,运行程序的结果如下;

在这里插入图片描述

Tomcat 服务器在 8081 端口运行

如果只配置 application.yml 和 application.yaml,程序运行结果如下:

在这里插入图片描述
Tomcat 服务器在 8082 端口运行

通过测试同一属性在三个文件中的配置,得出优先级:properties 最高,yml 次之,yaml 最低。

Spring Boot 除了支持配置文件属性配置,还支持 Java 系统属性和命令行参数的方式进行属性配置

  • Java系统属性:-Dserver.port=9000
  • 命令行参数:--server.port=9001

命令行参数优先级高于 Java 系统属性。

在 Spring Boot 项目打包后,若需配置属性(如端口号等),可通过 Java 系统属性命令行参数两种方式进行,具体操作如下:

  1. 项目打包前提

    • 打包需执行 Maven 的package生命周期,生成可运行的 jar 包。

    • 注意:Spring Boot 项目打包必须依赖spring-boot-maven-plugin插件,基于官方骨架创建的项目会自动引入该插件,无需手动添加。

  2. 运行打包后的 jar 包

    • 基本命令:

      java -jar 项目名.jar
      
    • (例如:java -jar spring-boot-web-config.jar,可通过tab键自动补全 jar 包名称)

  3. 配置 Java 系统属性

    • 格式:在java命令后、-jar之前,使用-Dkey=value格式配置。

    • 示例:配置 Tomcat 端口号为 9000

      java -Dserver.port=9000 -jar spring-boot-web-config.jar
      
  4. 配置命令行参数

    • 格式:在 jar 包名称之后,使用--key=value格式配置。

    • 示例:配置 Tomcat 端口号为 10010

      java -jar spring-boot-web-config.jar --server.port=10010
      

五种配置方式的优先级:从高到低依次为命令行参数、Java 系统属性、properties 配置文件、yml 配置文件、yaml 配置文件。

Bean 管理

获取 Bean

默认情况下,Spring 项目启动时,会把 Bean 都创建好放在 IOC 容器中,如果想要主动获取这些 Bean,可以通过以下方式:

  • 根据 name 获取 Bean:Object getBean(String name)
  • 根据类型获取 Bean:<T> T getBean(Class<T> requiredType)
  • 根据 name 获取 Bean(带类型转换):<T> T getBean(String name, Class<T> requiredType)

在测试类中加入以下代码进行获取 Bean 的测试:

@Autowired
// 获取ApplicationContext对象
private ApplicationContext applicationContext;
@Test
public void testGetBean(){// 根据Bean的名称获取DeptController bean1 = (DeptController) applicationContext.getBean("deptController");System.out.println(bean1);// 根据Bean的类型获取DeptController bean2 = applicationContext.getBean(DeptController.class);System.out.println(bean2);// 根据Bean的名称和类型获取DeptController bean3 = applicationContext.getBean("deptController", DeptController.class);System.out.println(bean3);
}

测试运行结果如下:

在这里插入图片描述

三次调用 getBean 方法获取同一 bean 对象,其地址值相同,说明默认情况下 bean 是单例的。

Spring 项目启动时创建所有 bean 对象并放在 IOC 容器中,这仅针对默认情况下单例且非延迟加载的 bean,bean 的创建时间还受作用域和延迟初始化影响

Bean 的作用域

bean 是单例还是多例取决于其作用域,Spring 中 bean 支持五种作用域,重点关注前两种,后三种在 web 环境生效:

作用域说明
singleton在整个 Spring 容器中,同名称的 bean 对象只有一个实例,即单例,是作用域的默认值
prototype代表非单例,每一次使用该 bean 对象时,都会创建一个新的实例对象
request代表每一次请求对应一个实例对象
session代表每一次会话对应一个新的实例对象
application代表每一个应用对应一个实例对象

默认情况下,未设置作用域的 bean 是单例的,在 Spring 项目启动、IOC 容器创建时就会实例化并放到容器中,多次获取的是同一个对象。

设置 bean 作用域的方式:可以借助 Spring 中的 @Scope 注解来配置 bean 的作用域。

在要获取 Bean 的类上添加 @Scope("prototype"),运行前面的测试代码,结果如下:

在这里插入图片描述

延迟初始化注解 @lazy:在类上添加 @lazy 注解后,bean 会延迟初始化,延迟到第一次使用的时候实例化。

注意事项:

  • 默认作用域为 singleton,默认单例 bean 在容器启动时创建,可通过 @lazy 延迟到第一次使用时创建
  • prototype 非单例 bean 每次使用都会创建新实例

第三方 Bean

第三方 Bean 配置的必要性:项目中引入的第三方依赖提供的类(如 dom4j 中的 SAXReader),若每次使用都新建对象会耗费资源,需交给 Spring 的 IOC 容器管理,通过依赖注入使用。

第三方 Bean 配置的特殊之处:第三方类是只读的,无法直接在类上添加 @Component 及其衍生注解声明为 bean,需使用 @Bean 注解。

@Bean 注解的使用方法:在方法上添加 @Bean 注解,方法返回值为要管理的第三方 Bean 对象,Spring 会将方法返回值交给 IOC 容器管理,后续可通过 @Autowired 注入使用。

第三方 Bean 配置的位置:建议单独定义配置类(用 @Configuration 标识),在配置类中集中配置第三方 bean。

第三方 Bean 的名称规则:可通过 @Bean 的 name 或 value 属性指定名称,二者互为别名;未指定时,默认名称为方法名。
第三方 Bean 声明时的依赖注入:在定义第三方 bean 的方法中声明对应类型的形参,Spring 容器会根据类型自动装配 IOC 容器中的对应 Bean 对象。

Spring Boot 底层原理

Spring Boot 简化开发的原因:底层提供起步依赖和自动配置两个重要功能。起步依赖简化 pom 文件依赖配置,解决 Spring 框架依赖配置繁琐问题;自动配置简化框架使用时 Bean 的声明和配置,引入起步依赖后常见配置已存在,可直接使用。

起步依赖

以 Web 程序开发为例,使用 Spring 框架需引入多个依赖且版本需匹配,而使用 Spring Boot 只需引入对应的起步依赖(如 web 开发的 spring-boot-starter-web,aop 开发的 spring-boot-starter-aop)。其原理是 Maven 的依赖传递,起步依赖集成了开发所需的常见依赖,引入一个起步依赖后,其他依赖会通过依赖传递自动引入(若 A 依赖 B,B 依赖 C,C 依赖 D,引入 A 则 B、C、D 也会被引入)。

自动配置

自动配置的定义:指 Spring Boot 项目启动时,除了用户自己定义的 Bean 对象外,Spring Boot 会自动创建一些内置的配置类及 Bean 对象并放入 IOC 容器,使用户在开发时无需手动声明即可直接使用,简化开发,省去繁琐配置。

通过启动 Spring Boot 工程,在控制台的 Bean 中可查看所有 Bean 对象及配置类,包括用户自己定义的和 Spring Boot 自动加载的配置类及其生成的 Bean 对象

在这里插入图片描述

核心原理

自动配置的实现依赖 3 个关键机制:@EnableAutoConfiguration 注解SPI 机制(META-INF/spring.factories)条件注解(@Conditional)。三者协同工作,流程如下:

  1. 触发点:@SpringBootApplication 注解

SpringBoot 项目的启动类通常标注@SpringBootApplication,它是一个组合注解,包含 3 个核心注解:

  • @SpringBootConfiguration:标记当前类为配置类(类似@Configuration)。
  • @ComponentScan:默认扫描启动类所在包及其子包(但自动配置不依赖它,而是通过其他机制加载外部包的 Bean)。
  • @EnableAutoConfiguration自动配置的 “开关”,正是这个注解触发了后续的自动配置流程。
  1. 核心:@EnableAutoConfiguration 的作用

@EnableAutoConfiguration通过@Import(AutoConfigurationImportSelector.class)导入了AutoConfigurationImportSelector类,这个类是自动配置的 “核心执行者”,主要做两件事:

  • 加载候选配置类:扫描类路径下所有META-INF/spring.factories文件,读取其中org.springframework.boot.autoconfigure.EnableAutoConfiguration对应的配置类全类名(这些是 “候选自动配置类”)。
  • 筛选有效配置类:通过spring.factories加载的候选配置类会经过条件注解(如@ConditionalOnClass)的筛选,只有满足条件的配置类才会被真正加载到 IOC 容器。
  1. SPI 机制:META-INF/spring.factories 的作用

META-INF/spring.factories是 Java 的 SPI(Service Provider Interface)机制在 SpringBoot 中的应用,用于声明 “自动配置类” 的位置
格式如下(key 固定为org.springframework.boot.autoconfigure.EnableAutoConfiguration,value 为自动配置类的全类名列表):

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.MyAutoConfiguration,\
com.example.OtherAutoConfiguration

当项目启动时,AutoConfigurationImportSelector会读取所有依赖中的spring.factories,收集所有声明的自动配置类,作为候选者。

  1. 条件注解:筛选有效的配置类

候选配置类不会全部生效,需要通过条件注解判断是否满足生效条件。常见的条件注解有:

  • @ConditionalOnClass:类路径下存在指定类时,配置类才生效(如引入spring-web依赖后,DispatcherServlet.class存在,Web 相关配置才生效)。
  • @ConditionalOnMissingBean:容器中不存在指定 Bean 时,配置类才生效(允许开发者自定义 Bean 覆盖默认配置)。
  • @ConditionalOnProperty:配置文件中存在指定属性时生效(如server.port配置触发端口绑定)。

只有满足所有条件的配置类,才会被 Spring 实例化,其内部定义的 Bean 才会被注册到 IOC 容器。

总结流程:

  1. 启动类标注@SpringBootApplication,触发@EnableAutoConfiguration
  2. AutoConfigurationImportSelector扫描所有META-INF/spring.factories,收集候选自动配置类。
  3. 候选配置类通过条件注解筛选,保留有效配置类。
  4. 有效配置类被加载,其内部的 Bean(如DataSourceDispatcherServlet)被注册到 IOC 容器。
实例说明

下面通过两个例子(自定义 starter 和 SpringBoot 自带 starter)直观理解自动配置。

例 1:自定义一个 “日志 starter”

假设我们要开发一个my-log-starter,功能是:引入后自动配置一个LogServiceBean,用于打印日志。

步骤 1:定义核心 Bean 和配置类

  • LogService:需要被自动配置的 Bean。

    public class LogService {public void log(String message) {System.out.println("[MyLog] " + message);}
    }
    
  • LogAutoConfiguration:自动配置类,负责注册LogService

    @Configuration  // 标记为配置类
    @ConditionalOnClass(LogService.class)  // 类路径存在LogService时生效
    public class LogAutoConfiguration {// 注册LogService到IOC容器@Bean@ConditionalOnMissingBean  // 若用户自定义了LogService,则不使用默认的public LogService logService() {return new LogService();}
    }
    

步骤 2:通过 spring.factories 声明自动配置类

src/main/resources下创建META-INF/spring.factories,声明LogAutoConfiguration为候选配置类:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.log.LogAutoConfiguration

步骤 3:使用 starter

  • 其他项目引入

    my-log-starter
    

    依赖后,启动项目时:

    1. AutoConfigurationImportSelector读取spring.factories,发现LogAutoConfiguration
    2. 检查到类路径存在LogService.class(依赖已引入),且容器中没有自定义的LogService,满足条件。
    3. LogAutoConfiguration生效,logService()方法被执行,LogServiceBean 被注册到 IOC 容器。
  • 开发者可直接注入使用:

    @RestController
    public class TestController {@Autowiredprivate LogService logService;  // 直接使用自动配置的Bean@GetMapping("/test")public String test() {logService.log("测试日志");  // 输出:[MyLog] 测试日志return "ok";}
    }
    
例 2:SpringBoot 自带的 spring-boot-starter-web

引入spring-boot-starter-web后,SpringBoot 会自动配置 Web 开发所需的核心组件(如 Tomcat、DispatcherServlet),原理如下:

  1. 依赖引入starter-web包含spring-webspring-webmvctomcat-embed-core等依赖。
  2. 自动配置类spring-boot-autoconfigure包的META-INF/spring.factories中声明了DispatcherServletAutoConfigurationTomcatAutoConfiguration等配置类。
  3. 条件判断:
    • TomcatAutoConfiguration通过@ConditionalOnClass(Tomcat.class)判断:因引入了tomcat-embed-core,Tomcat 类存在,配置生效,自动启动内嵌 Tomcat。
    • DispatcherServletAutoConfiguration通过@ConditionalOnClass(DispatcherServlet.class)判断:因引入spring-webmvc,DispatcherServlet 类存在,配置生效,注册DispatcherServlet到容器。
  4. 最终效果:开发者无需手动配置 Tomcat 和 DispatcherServlet,引入依赖即可开发 Web 接口。
关键总结
  1. 自动配置的核心是:通过 @EnableAutoConfiguration 触发,SPI 机制加载候选配置类,条件注解筛选有效配置类
  2. 开发者可通过自定义 starter(含spring.factories和自动配置类)实现自动配置,也可通过@ConditionalOnMissingBean等注解覆盖默认配置。
  3. SpringBoot 的 starter(如webdata-jpa)都是基于此原理实现,极大简化了配置流程。

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

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

相关文章

基于Redisson的分布式锁原理深度解析与优化实践

基于Redisson的分布式锁原理深度解析与优化实践 分布式环境下&#xff0c;锁的实现至关重要。本文将从技术背景与应用场景出发&#xff0c;结合核心原理、关键源码、实际示例&#xff0c;深入剖析Redisson分布式锁的实现机制&#xff0c;并给出性能优化建议&#xff0c;帮助后端…

室外 3DVG 基准

室外 3DVG基准&#xff08;按重要性与被引用频率&#xff09; Talk2Car / Talk2Car-3D (2019 / 衍生) — 对象 referral&#xff08;驾驶场景&#xff09; 说明&#xff1a;最早的自然语言 → 驾驶场景对象引用数据集之一&#xff08;原 Talk2Car 是以 nuScenes 为底并提供自然…

Jenkins安装部署(Win11)和常见配置镜像加速

一、安装前准备 本文使用的Jenkins Windows一键安装包&#xff0c;JDK事先配置好环境变量&#xff0c;Jenkins版本&#xff1a; Jenkins下载地址&#xff1a;jenkins一键安装包v2-479-1.msi资源-CSDN下载 二、Jenkins安装部署 1、下载Jenkins &#xff0c;点击下一步下一步…

Windows MCP.Net:革命性的 .NET Windows 桌面自动化 MCP 服务器

&#x1f4cb; 目录 项目概述 核心技术架构 功能特性详解 技术实现亮点 安装与配置 实战应用场景 代码示例与API详解 性能优化与最佳实践 未来发展规划 总结 项目概述 在人工智能快速发展的今天&#xff0c;AI 助手与操作系统的深度集成成为了一个重要趋势。Window…

Java ArrayList的介绍及用法

十分想念顺店杂可。。。ArrayList 是 Java 集合框架中最常用的类之一&#xff0c;实现了 List 接口&#xff0c;底层基于动态数组实现&#xff0c;支持动态扩容&#xff0c;相比普通数组更灵活。以下是其详细介绍及用法&#xff1a;一、核心特性动态大小&#xff1a;无需预先指…

Docker 命令大全及使用场景总结

一、容器生命周期管理1. 创建并运行容器docker run [选项] 镜像名 [命令]常用选项&#xff1a;-d&#xff1a;后台运行&#xff08;detached&#xff09;-it&#xff1a;交互式终端&#xff08;如 -it ubuntu bash&#xff09;--name&#xff1a;指定容器名称-p 主机端口:容器端…

简单的 HTTPS 学习

简单的 HTTPS 学习 1. 需求 现在使用的服务是HTTP调用形式&#xff0c;服务可能会有调用外围https形式的服务&#xff0c;简单了解了一下&#xff0c;然后写了一个简单的例子进行记录。 HTTP&#xff08;超文本传输协议&#xff09; 是一种用于传输超文本的应用层协议&#…

[系统架构设计师]系统质量属性与架构评估(八)

[系统架构设计师]系统质量属性与架构评估&#xff08;八&#xff09; 一.软件系统质量属性 1.基本概念 软件系统质量属性&#xff1a;可测量或可测试的属性 开发期质量属性&#xff0c;运行期质量属性面向架构评估的质量属性&#xff1a;1.可用性&#xff1a; 提升策略 错误检测…

【R语言】R 语言中 gsub 与正则表达式详解(含 POSIX 与 Perl 风格实例)

R 语言中 gsub 与正则表达式详解&#xff08;含 POSIX 与 Perl 风格实例&#xff09; 在 R 语言中&#xff0c;字符串处理是非常常见的需求&#xff0c;R 语言中的 gsub() 函数则具有字符串替换的功能。本文将通过两个实例&#xff0c;帮助你深入理解 R 的 gsub()、POSIX 字符…

EN55035多媒体设备电磁兼容性抗干扰要求标准

EN55035 是一项由欧洲标准化委员会制定的电磁兼容性&#xff08;EMC&#xff09;标准&#xff0c;全称为《多媒体设备的电磁兼容性要求》。该标准主要针对多媒体设备的电磁辐射和抗干扰能力进行规范&#xff0c;确保这类设备在电磁环境中能够正常工作&#xff0c;同时不对其他设…

计算分组内时间列的最大差值

计算分组内时间列的最大差值 在 Pandas 中&#xff0c;要计算每个分组内 time 列的最大值与当前行值的差值&#xff0c;需结合 groupby() 和 transform() 方法。核心步骤如下&#xff1a;分组计算最大值 使用 transform(max) 获取每个分组中 time 列的最大值&#xff0c;结果会…

CUDA 编程笔记:CUDA延迟隐藏

一、核心概念&#xff1a;延迟隐藏&#xff08;Latency Hiding&#xff09;是 GPU 通过多线程机制掩盖指令延迟的关键技术。当某些线程束&#xff08;warp&#xff09;因指令延迟&#xff08;如内存访问或算术计算&#xff09;而等待时&#xff0c;其他就绪线程束会立即被调度执…

MySQL工具包中的其他程序

虽然有很多不同的程序&#xff0c;但有些选项是公共的&#xff0c;比兔用户名和密码&#xff0c;使用方法和MySQL相同&#xff0c;在这里统一列出&#xff0c;后面我们介绍不同的工具时&#xff0c;只讨论个性的选项以及作用以下是常用的MySQL程序&#xff1a;程序名作用mysqld…

C#WPF实战出真汁09--【消费开单】--选择菜品

1、功能介绍当选择一个空桌时&#xff0c;必须先开台才能开单&#xff0c;可以先开台&#xff0c;再开单&#xff0c;也可以开台的同时开单当选择一个用餐中的餐桌时&#xff0c;必须显示该桌前面已经点好的菜品&#xff0c;同时可以继续点餐或结账所以无论哪个功能都涉及选择菜…

大厂语音合成成本深度对比:微软 / 阿里 / 腾讯 / 火山 API 计费拆解与技术选型指南

在 AI 配音、智能客服、教育音频等场景爆发的当下&#xff0c;语音合成 API 已成为企业技术栈中的核心组件。然而&#xff0c;不同云厂商的计费规则差异显著&#xff0c;短文本 / 长文本计费分离、预付费 / 后付费价格梯度悬殊、音色授权费暗藏成本陷阱等问题&#xff0c;常导致…

Flutter开发 网络请求

HttpClient&#xff08;dart自有&#xff09; 1.get 点击请求按钮获取数据&#xff0c;解析数据获取单词展示到屏幕上。class MyState extends State {String info "暂无数据";List<Widget> texts [];overridevoid initState() {super.initState();}override…

vscode中用python调用matlab的函数(环境安装)

本实践适用于WIN11-x64和ubuntu22.04-x64系统&#xff0c;其余系统和架构未验证。 效果展示 1.环境要求 MATLAB Engine API for Python 的系统要求&#xff1a;参阅此官方文档MATLAB 与 Python 的版本兼容性&#xff1a;参阅此官方文档 2.安装步骤 安装Vscode&#xff08;不…

【数据分享】大清河(大庆河)流域上游土地利用

而今天要说明数据就是大清河&#xff08;大庆河&#xff09;流域上游土地利用。数据介绍大清河&#xff0c;又称大庆河&#xff0c;作为海河流域的重要支流&#xff0c;其流域上游地区不仅是区域水资源调控的关键节点&#xff0c;更是生态保护与经济发展的重要载体。以下从地理…

图论——Djikstra最短路

原理解释 首先解释一下它大概的应用场景以及原理&#xff1a;现在有这么一张图&#xff0c;图上各点之间都有一定的边权或者说是距离。给定你一个起点&#xff08;例如点1&#xff09;&#xff0c;让你求这个点到图上所有点的最短距离是多少&#xff1f; 这个问题比较平常&…

kafka初步介绍

Kafka角色介绍TopicTopic主题的意思&#xff0c;消费者必须指定主题用于的消息发送&#xff0c;生产者也必须指定主题用于消息的接收。topic只是逻辑上的划分。partitionpartition是分区的意思&#xff0c;他的主要作用是将发送到一个topic的数据做一个划分。如果有4个partitio…