SpringBoot开发秘籍【个人八股】

介绍一下 SpringBoot?

Spring Boot极大地简化了 Spring 应用的开发和部署过程。

以前我们用 Spring 开发项目的时候,需要配置一大堆 XML 文件,包括 Bean 的定义、数据源配置、事务配置等等,非常繁琐。而且还要手动管理各种 jar 包的依赖关系 ,很容易出现版本冲突的问题。部署的时候还要单独搭建 Tomcat 服务器,整个过程很复杂。

什么是数据源?

数据源 JDBC 规范定义的接口,本质是一个 数据库连接池 ,它封装了数据库连接的创建、复用和释放逻辑,应用程序通过它获取连接即可执行 SQL ,无需关心连接的生命周期管理。

"约定大于配置"是 Spring Boot 最核心的理念。它预设了很多默认配置,比如默认使用内嵌的 Tomcat 服务器,默认的日志框架是 Logback 等等。这样,我们开发者就只需要关注业务逻辑!

自动装配也是 Spring Boot 的一大特色,它会根据项目中引入的依赖自动配置合适的 Bean。比如说,我们引入了 Spring Data JPA,Spring Boot 就会自动配置数据源;比如说,我们引入了 Spring Security,Spring Boot 就会自动配置安全相关的 Bean。

Spring Boot 还提供了很多开箱即用的功能 ,比如 Actuator 监控、DevTools 开发工具、Spring Boot Starter 等等。Actuator 可以让我们轻松监控应用的健康状态、性能指标等;DevTools 可以加快开发效率,比如自动重启、热部署等;Spring Boot Starter 则是一些预配置好的依赖集合,让我们可以快速引入某些常用的功能

简单来讲,就是springboot相较于传统的spring框架是起到了一个简化开发的作用

如果是传统的spring开发,我们需要写很多的xml配置文件,需要手动管理jar包之间的相互依赖,以及bean的配置,数据源配置,事务的配置!还需要手动搭建tomcat,整个开发的前置过程是非常繁琐的!

因此,我们引入了springboot这个spring快速开发的脚手架,是基于spring的基础上,预设了很多的基础配置,让开发者更多的去关注业务的开发!自动装配是springboot的一大特色,比如我们需要引入某一个功能的时候,springboot就会自动配置合适的bean。

同时springboot也提供了很多开箱即用的功能,springboot starter预设好了很多配置好的依赖集合,就不需要去处理依赖之间的冲突问题!可以帮助我们快速的引入对应的功能

Spring Boot 和 Spring MVC / Spring 有什么区别?

我目前了解到的点:

  1. springboot是约定大于配置,springboot已经帮助我们完成了项目运行时需要的大部分的配置工作!最基础的,最底层的配置,都已经是springboot帮助我们配置完成了。Spring Boot :不是新框架,而是基于 Spring 的 快速开发脚手架,主要解决配置繁琐、依赖冲突、部署复杂的问题。

  2. springMVC的话,是model-view-controller模型,而在现在的前后端分离分离开发模式当中,对于view部分的工作已经不再是后端人员需要负责的内容,Spring Boot 通过 spring-boot-starter-web 自动集成并配置了整个 Spring MVC Web 开发环境。

  3. 在前后端分离项目中,后端通常不再返回页面,而是返回 JSON,所以 View 层弱化了,但 Spring MVC 的整体机制仍然存在。

  4. spring的话是整个spring的全家桶,如果不用springboot来辅助我们去进行配置,就需要开发人员来对spring全家桶当中的每个工具库进行一个单独的配置工作!同时也不方便我们对依赖进行统一的管理!而且需要考虑依赖之间的冲突问题!

优化一句话版

Spring 是一个基础框架,核心能力是 IoC、AOP、事务管理等;

Spring MVC 是 Spring 中专门用于 Web 开发的模块,负责处理 HTTP 请求和响应,核心是 DispatcherServlet;

Spring Boot 不是替代 Spring 的新框架,而是基于 Spring 的快速开发脚手架,通过自动配置、starter 依赖、内置 Tomcat 和统一版本管理,简化了 Spring 项目的开发和部署。

Spring Boot 自动配置原理是什么?

我的理解:

  1. springboot进行自动配置,springboot内置了一个IOC容器,可以将常用的bean都放到这个IOC容器里面去!

  2. 当我们需要用到对应的工具的时候,就直接从IOC容器进行依赖注入即可

改进

🌟Spring Boot的自动装配原理了解吗?

  1. 在 Spring Boot 中,开启自动装配 的注解是@EnableAutoConfiguration。这个注解会告诉 Spring 去扫描所有可用的自动配置类

  2. Spring Boot 为了进一步简化,把这个注解包含到了 @SpringBootApplication 注解中。也就是说,当我们在主类上使用 @SpringBootApplication 注解时,实际上就已经开启了自动装配。

  3. main 方法运行的时候 ,Spring 会去类路径下找 spring.factories 这个文件,读取里面配置的自动配置类列表。比如在我们的技术派项目中,paicoding-core 和 paicoding-service 模块里都有 spring.factories,分别注册了 ForumCoreAutoConfig 和 ServiceAutoConfig,这两个配置类就会在项目启动的时候被自动加载。

  4. 然后每个自动配置类内部 ,通常会有一个 @Configuration 注解 ,同时结合各种 @Conditional 注解来做条件控制 。像技术派的 RabbitMqAutoConfig 类,就用了 @ConditionalOnProperty 注解来判断配置文件里有没有开启 rabbitmq.switchFlag,来决定是否初始化 RabbitMQ 消费线程。

  5. 另外一个常见的场景是自动注入 Bean ,比如技术派的 ServiceAutoConfig 中就用了 @ComponentScan 来扫描 service 包,@MapperScan 扫描 MyBatis 的 mapper 接口,实现业务层和 DAO 层的自动装配。

执行过程

具体的执行过程可以总结为:Spring Boot 项目在启动时加载所有的自动配置类,然后逐个检查它们的生效条件,当条件满足时就实例化并创建相应的 Bean。

自动装配的执行时机

Spring 容器启动的时候。具体来说是在 ConfigurationClassPostProcessor 这个 BeanPostProcessor 中处理的,它会解析 @Configuration 类,包括通过 @Import 导入的自动配置类。

一句话总结:

Spring Boot 自动装配就是:根据 classpath 依赖、配置文件和容器中已有 Bean,按条件自动加载配置类并创建 Bean。

Spring Boot 启动流程大概是什么?

对于这个部分我没有深入的去想过

改进:

Spring Boot 启动流程可以按这条主线记:

main() 方法执行 → 创建 SpringApplication → 准备环境 → 创建 Spring 容器 → 加载 Bean 定义 → 刷新容器 → 启动 Web 服务器 → 执行启动后回调

①、创建 SpringApplication 实例,并识别应用类型,比如说是标准的 Servlet Web 还是响应式的 WebFlux,然后准备监听器和初始化监听容器。

②、创建并准备 ApplicationContext,将主类作为配置源进行加载。

③、刷新 Spring 上下文,触发 Bean 的实例化,比如说扫描并注册 @ComponentScan 指定路径下的 Bean。

④、触发自动配置,在 Spring Boot 2.7 及之前是通过 spring.factories 加载的,3.x 是通过读取 AutoConfiguration.imports,并结合 @ConditionalOn 系列注解依据条件注册 Bean。

⑤、如果引入了 Web 相关依赖,会创建并启动 Tomcat 容器,完成 HTTP 端口监听。

Spring Boot 启动时,会先执行 SpringApplication.run(),然后创建 SpringApplication 对象,准备运行环境,加载配置文件,创建 Spring 容器。接着解析启动类上的 @SpringBootApplication,完成组件扫描和自动装配。之后调用容器的 refresh() 方法,完成 Bean 的创建、依赖注入和初始化。如果是 Web 项目,还会启动内置 Tomcat。最后执行 ApplicationRunnerCommandLineRunner 等启动后回调。

Spring Boot 3 和 Spring Boot 2 有什么变化?

Spring Boot 3 相比 Spring Boot 2,最大的变化是最低要求 Java 17,底层升级到了 Spring Framework 6;同时从 Java EE 的 javax.* 包迁移到了 Jakarta EE 的 jakarta.* 包,这是升级时最容易出问题的地方。

另外,Spring Boot 3 对自动配置机制、安全配置、AOT 编译、GraalVM 原生镜像和可观测性都做了增强。Spring Security 也升级到了 6,常见的 WebSecurityConfigurerAdapter 配置方式被新的 SecurityFilterChain 方式替代。

Spring Boot 3 是基于 Java 17、Spring 6 和 Jakarta EE 的新一代 Boot,核心变化是版本升级、javaxjakarta 迁移,以及原生镜像和可观测性的增强。

你项目里的接口是怎么分层的?

我的回答:

  1. 我的项目内部接口分层采用的是controller层->service层->mapper层->数据库

  2. 首先controller负责接收前端传递过来的所有请求,并将这些请求适当的做一些处理:

    1. 比如说前端传递过来的参数是非常多的,这每一个参数都有可能对应不同的service层接口!

    2. 因此需要对传递过来的参数进行分析,分别取调用不同的业务层service接口

  3. 接着是service层接口的调用,主要的业务逻辑都是在这一层进行实现的;如果需要对应的数据,就去调用对应的mapper层接口去获取数据

  4. mapper层接口主要是实现了对数据库的操作,实现了data的CRUD操作!

我项目里的接口主要按照 Controller、Service、Mapper 三层来拆分。Controller 负责接收请求和返回结果,Service 负责核心业务逻辑,Mapper 负责数据库操作。同时会区分 DTO、VO、Entity,避免前端参数、业务对象和数据库对象混在一起。这样做的好处是职责清晰、代码解耦,也方便后期维护和扩展。

Spring Boot 中如何统一异常处理?

我的理解:这个点需要考虑结合技术派项目中的全局异常处理器来回答!

这个部分对于全局异常处理的注解有点遗忘了,需要补充一下,对于异常处理这部分感觉还是有点薄弱,需要考虑补充一下这个部分的知识点!

Spring Boot 中通常使用 @RestControllerAdvice@ExceptionHandler 做统一异常处理。 @RestControllerAdvice 用来定义全局异常处理类,@ExceptionHandler 用来捕获指定类型的异常。

如何做参数校验?

对于这个部分也是一块空白?

Spring Boot 参数校验一般使用 spring-boot-starter-validation。在请求 DTO 字段上加 @NotNull@NotBlank@Size@Email 等注解,然后在 Controller 参数上加 @Valid@Validated 触发校验。校验失败后,通过全局异常处理器捕获 MethodArgumentNotValidException 等异常,统一返回错误信息。

参数校验就是:DTO 上写校验规则,Controller 用 @Valid/@Validated 触发校验,异常由全局异常处理统一返回。

如何做接口幂等?

我的理解:

  1. 同一个请求执行一次和执行多次,最终结果是一致的,不会因为重复请求导致重复下单、重复支付、重复扣库存。

  2. 可以考虑的解决方案:首先最先相当的是用redis+SETNX的方式,只有在这个key不存在的情况下,key才能创建成功,并执行后续的业务代码;否则key创建失败,保证幂等性!

  3. 可以考虑使用token或者数据库;数据库比如订单表中 order_no 加唯一索引:但是需要考虑到可能会给数据库带来比较大的压力,如果是redis可以做的事情,为什么需要推到数据库身上呢?

  4. 可以考虑用状态机和乐观锁,这两个都有一个思想就是去检查当前的状态/版本号,这是两者的一个相似之处!

接口幂等主要是为了防止重复提交、网络重试、MQ 重复消费等场景导致数据重复处理。常见做法有几种:第一种是 token 机制,请求前生成 token,请求时校验并删除;第二种是 Redis 的 SETNX,用请求唯一 ID 作为 key,只有第一次请求能成功;第三种是数据库唯一索引,比如订单号唯一,防止重复插入;第四种是通过业务状态机判断,比如支付回调重复到达时,如果订单已经支付,就直接返回成功,不再重复处理。

接口幂等就是给请求或业务数据加一个唯一标识,再结合 Redis、数据库唯一索引或状态判断,保证重复请求不会重复执行业务逻辑。

如何做全局响应封装?

我的理解

可以与前端开发人员进行沟通,确定我后端数据返回前端的格式/方式,用统一的方式对数据进行一个封装的操作,便于前端进行解析和处理

Spring Boot 中做全局响应封装,一般会先定义统一返回对象,比如 Result<T>,里面包含 codemessagedata。然后可以在 Controller 中手动返回 Result.success(data),也可以使用 ResponseBodyAdvice 对接口返回值进行统一包装。成功响应统一封装,异常响应则配合全局异常处理器返回统一错误格式。

一句话总结:

全局响应封装就是通过统一 Result 对象,加上 ResponseBodyAdvice 和全局异常处理,让所有接口返回固定格式的数据。

IOC

说一说什么是IoC?

IoC 的全称是 Inversion of Control,也就是控制反转。这里的"控制"指的是对象创建和依赖关系管理的控制权

请你说一说什么是控制反转?

这里的"控制"指的是对象创建和依赖关系管理的控制权

以前我们写代码的时候,如果 A 类需要用到 B 类,我们就在 A 类里面直接 new 一个 B 对象出来,这样 A 类就控制了 B 类对象的创建。

复制代码

// 传统方式:对象主动创建依赖 public class UserService { private UserDao userDao; public UserService() { // 主动创建依赖对象 this.userDao = new UserDaoImpl(); } }

有了 IoC 之后,这个控制权就"反转"了,不再由 A 类来控制 B 对象的创建,而是交给外部的容器来管理。

复制代码

/** * 使用 Spring IoC 容器来管理 UserDao 的创建和注入 */ @Service public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; // 不需要主动创建 UserDao,由 Spring 容器注入 public BaseUserInfoDTO getAndUpdateUserIpInfoBySessionId(String session, String clientIp) { // 直接使用注入的 userDao return userDao.getBySessionId(session); } }

对于DI你了解多少?

IoC 的思想是把对象创建和依赖关系的控制权由业务代码转移给 Spring 容器。

而 DI,也就是依赖注入,它是实现 IoC 这种思想的具体技术手段。在 Spring 里,我们用 @Autowired 注解就是在使用 DI 的字段注入方式。

为什么要用到IOC容器?

在日常开发中,如果我们需要实现某一个功能,可能至少需要两个以上的对象来协助完成,在没有 Spring 之前,每个对象在需要它的合作对象时,需要自己 new 一个,比如说 A 要使用 B,A 就对 B 产生了依赖,也就是 A 和 B 之间存在了一种耦合关系。

有了 Spring 之后,创建 B 的工作交给了 Spring 来完成,Spring 创建好了 B 对象后就放到容器中,A 告诉 Spring 我需要 B,Spring 就从容器中取出 B 交给 A 来使用。

至于 B 是怎么来的,A 就不再关心了。

这就是 IoC 的好处,它降低了对象之间的耦合度 ,让每个对象只关注自己的业务实现,不关心其他对象是怎么创建的。

框架

Spring Boot 项目从启动到处理请求

一、整体框架一句话

springboot通过starter来引入依赖,通过自动配置的方式来实现bean的生命周期,Bean的生命周期由IOC容器进行管理!运行时,请求进入springMVC,在请求的过程中会一次经过过滤器和拦截器,同时可以考虑使用AOP来对业务进行增强处理!其中事务就是用AOP机制来实现的。

可以这样回答:

Spring Boot 项目启动时,首先通过 Starter 引入相关依赖,比如 Web、MyBatis、Redis 等。然后自动配置机制会根据 classpath、配置文件和条件注解自动创建对应的 Bean。Bean 的创建和依赖注入由 IOC 容器完成,同时 Bean 会经历实例化、属性注入、初始化、后置处理等生命周期。在 Bean 生命周期中,Spring 还会通过 BeanPostProcessor 创建 AOP 代理对象,事务、日志等功能就是基于 AOP 实现的。

项目启动完成后,一个请求会先经过 Filter,再进入 Spring MVC 的 DispatcherServlet,然后通过 HandlerMapping 找到 Controller,通过 HandlerAdapter 调用目标方法。Controller 调用 Service 时,如果 Service 上有 @Transactional,实际执行的是代理对象,代理对象会在方法执行前开启事务,执行成功后提交,异常时回滚。

所以整体来看,Starter 负责依赖整合,自动配置负责创建默认配置,IOC 负责管理 Bean,Bean 生命周期负责 Bean 的创建和初始化,Spring MVC 负责请求处理,Filter、Interceptor、AOP 负责增强逻辑,而事务传播机制就是 AOP 在业务层的典型应用。

二、启动阶段:Starter → 自动配置 → IOC → Bean 生命周期

  1. Spring Boot Starter 机制

Starter 的作用是:帮我们把一类功能需要的依赖和默认配置整合好。

Starter 主要解决的是:依赖整合 + 版本管理 + 自动配置入口。

  1. 自动配置

自动配置的作用是:根据当前项目引入的依赖、配置文件和已有 Bean,自动帮我们创建需要的 Bean。

核心思想是:你引了什么依赖、配了什么参数,Spring Boot 就帮你装配什么功能。

  1. IOC

IOC 的作用是:把对象的创建、依赖注入、生命周期管理交给 Spring 容器。

所以 IOC 解决的是:对象创建和对象依赖关系管理的问题。换句话讲就是不需要手动的去new一个类!

  1. Bean 生命周期

Bean 生命周期描述的是:一个 Bean 从创建到销毁的完整过程。

复制代码

实例化 Bean ↓ 属性注入 ↓ Aware 回调 ↓ BeanPostProcessor 前置处理 ↓ 初始化方法 ↓ BeanPostProcessor 后置处理 ↓ 放入单例池 ↓ 销毁

这里和 AOP 有关系:

AOP 代理对象通常就是在 BeanPostProcessor 后置处理阶段生成的。

所以一个 Service Bean 最终放进容器里的,可能不是原始对象,而是代理对象。

三、运行阶段:Spring MVC 请求流程

Spring MVC 是 Spring 提供的 Web 模块,核心是 DispatcherServlet,它负责把请求分发到对应的 Controller 方法,并将结果转换成响应返回给前端。

复制代码

浏览器 / 前端请求 ↓ Filter 过滤器 ↓ DispatcherServlet ↓ HandlerMapping 找 Controller ↓ HandlerAdapter 调用 Controller ↓ Interceptor 拦截器 ↓ Controller ↓ Service ↓ Mapper / DAO ↓ 数据库 ↓ 返回 JSON

四、增强阶段:Filter / Interceptor / AOP

  1. Filter 过滤器

Filter 属于 Servlet 规范,不是 Spring MVC 专属。

它的位置最靠前:

请求 → Filter → DispatcherServlet

  1. Interceptor 拦截器

Interceptor 是 Spring MVC 提供的。

它的位置在 DispatcherServlet 之后、Controller 之前:

DispatcherServlet → Interceptor → Controller

  1. AOP

AOP 是面向切面编程,和 Web 不强绑定。

它增强的是方法调用:

Controller / Service / Mapper 方法执行前后

五、事务传播机制:AOP 的典型应用

事务传播机制主要解决:

多个加了 @Transactional 的方法互相调用时,事务之间如何协作的问题。

比如:

复制代码

A 方法有事务 ↓ 调用 B 方法 ↓ B 方法到底加入 A 的事务,还是开启新事务?

这就是传播机制。

六、把所有知识点串起来

复制代码

1. 项目启动时,SpringApplication.run() 开始启动 Spring Boot 项目。 2. Spring Boot 通过 Starter 引入相关依赖,比如 starter-web 引入 Spring MVC、Tomcat、Jackson。 3. 自动配置机制根据 classpath 依赖、配置文件和条件注解,自动加载配置类,注册 BeanDefinition。 4. IOC 容器负责创建 Bean,并完成依赖注入。 5. Bean 创建过程中会经历生命周期,比如实例化、属性注入、初始化、BeanPostProcessor。 6. AOP 代理对象通常在 BeanPostProcessor 后置处理阶段生成,所以事务、日志等功能可以对 Bean 方法进行增强。 7. 项目启动完成后,HTTP 请求先进入 Filter,再进入 Spring MVC 的 DispatcherServlet。 8. DispatcherServlet 通过 HandlerMapping 找到 Controller,再通过 HandlerAdapter 调用目标方法。 9. 调用 Controller 前后可能会经过 Interceptor。 10. Controller 调用 Service 时,如果 Service 方法有 @Transactional,实际调用的是 AOP 代理对象,由代理对象控制事务提交或回滚。 11. Service 调用 Mapper 访问数据库,最后结果通过 HttpMessageConverter 转成 JSON 返回前端。

相关推荐
IT_陈寒1 小时前
SpringBoot这个事务回滚的坑我算是踩明白了
前端·人工智能·后端
ch.ju1 小时前
Java Programming Chapter 4——Dynamic part
java·开发语言
隔窗听雨眠1 小时前
RPA + Java构建高并发智能抢票系统的完整实践
java·rpa·抢票·12306
专吃海绵宝宝菠萝屋的派大星1 小时前
spring Ai 开发的mcp-由sse改成Streamable HTTP
人工智能·spring·http
Chase_______1 小时前
【Java基础核心知识点全解·第0篇】Java开发环境搭建指南:JDK + IDEA 从安装配置到运行 HelloWorld
java·开发语言·intellij-idea
布吉岛的石头2 小时前
Java 程序员第 19 阶段:大模型Agent智能体入门:拆解自主任务编排原理
java·开发语言·人工智能
JackSparrow4142 小时前
彻底理解Java NIO(二)C语言实现 I/O多路复用+Reactor模式 服务器详解
java·linux·c语言·后端·nio·reactor模式
淘矿人2 小时前
Claude助力后端开发
java·开发语言·人工智能·python·github·php·pygame
JAVA面经实录9172 小时前
Java集合100道面试真题(背诵完整版)
java·python·面试