我要提问
ARTICLE DETAIL

资讯详情

前沿编程新知与开发实战干货的深度解读。

Spring Boot 核心知识点总结,面试再也不怕了!

Spring Boot 核心知识点总结,面试再也不怕了! 一、Spring Boot 概述1.1 为什么需要 Spring Boot传统 Spring 项目存在三大痛点依赖版本冲突手动管理依赖版本容易出现版本不兼容。配置繁琐大量 XML 或 Java 配置类启动慢、维护成本高。部署复杂需要外部 Servlet 容器打包、部署、运维链路长。Spring Boot 通过起步依赖、自动配置、内嵌容器三大核心能力系统性地解决了上述问题。1.2 核心特性特性说明起步依赖Starter将常用依赖以固定版本打包引入一个 starter 即可获得一组匹配依赖自动配置Auto Configuration根据类路径和已定义的 Bean自动完成大量默认配置内嵌容器内嵌 Tomcat、Jetty 或 Undertow可打成 JAR 包独立运行Actuator提供生产可用的监控端点如健康检查、指标、环境信息等外部化配置支持 properties、YAML、环境变量、命令行参数等多种来源且有明确优先级1.3 Spring Boot 与 Spring、Spring Cloud 的关系Spring核心框架提供 IoC、AOP、数据访问、Web 等基础能力。Spring Boot在 Spring 之上的快速开发脚手架解决配置和部署复杂度。Spring Cloud基于 Spring Boot 构建提供微服务治理能力如服务注册发现、配置中心、网关、熔断等。三者是层层递进、相互配合的关系面试中常常会考察对这一关系的理解。二、自动配置原理自动配置是 Spring Boot 面试中的绝对高频考点。要讲清楚自动配置必须从SpringBootApplication注解和SpringFactoriesLoader机制入手。2.1 SpringBootApplication 背后的三个注解SpringBootApplication是一个组合注解等价于同时声明了以下三个注解SpringBootConfiguration本质是Configuration标记当前类是配置类。EnableAutoConfiguration开启自动配置是核心所在。ComponentScan开启组件扫描默认扫描启动类所在包及其子包。简化源码结构javaTarget(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 { }2.2 自动配置的加载流程自动配置的入口是EnableAutoConfiguration其内部通过Import(AutoConfigurationImportSelector.class)导入选择器。整体流程如下启动类上的EnableAutoConfiguration触发AutoConfigurationImportSelector。该选择器调用SpringFactoriesLoader.loadFactoryNames方法。从类路径下所有META-INF/spring.factories文件以及 Spring Boot 2.7 之后推荐的META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中读取自动配置类全限定名。通过Conditional系列条件注解对候选配置类进行过滤。符合条件的配置类被加载为 Bean完成默认配置。核心流程伪代码javapublic class AutoConfigurationImportSelector { protected ListString getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) { // 从 META-INF/spring.factories 读取 EnableAutoConfiguration 对应的配置类列表 ListString configurations SpringFactoriesLoader.loadFactoryNames( getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader()); return configurations; } }2.3 条件注解体系自动配置之所以能“按需生效”依赖的是 Spring 提供的条件注解条件注解作用ConditionalOnClass当类路径下存在指定类时生效ConditionalOnMissingClass当类路径下不存在指定类时生效ConditionalOnBean当容器中存在指定 Bean 时生效ConditionalOnMissingBean当容器中不存在指定 Bean 时生效ConditionalOnProperty当配置文件中存在指定属性且值为指定值时生效ConditionalOnWebApplication当当前应用是 Web 应用时生效ConditionalOnExpression当 SpEL 表达式结果为 true 时生效经典应用场景引入spring-boot-starter-data-redis且类路径存在RedisTemplate相关类时RedisAutoConfiguration才会被激活。2.4 自定义 Starter 的思路创建配置工程定义自动配置类使用Configuration和Bean提供核心对象。在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports或spring.factories中注册配置类。通过ConfigurationProperties提供可配置属性。用ConditionalOnMissingBean等注解保证可被用户覆盖。单独拆分xxx-spring-boot-autoconfigure与xxx-spring-boot-starter两个模块。三、Spring Boot 启动流程Spring Boot 应用的启动本质是执行SpringApplication.run方法。3.1 启动流程图3.2 关键步骤详解创建 SpringApplication 实例推断应用类型有无 Web 环境加载ApplicationContextInitializer和ApplicationListener。准备环境创建ConfigurableEnvironment加载配置文件和环境变量并发布环境准备事件。创建应用上下文根据应用类型创建AnnotationConfigApplicationContext、AnnotationConfigServletWebServerApplicationContext或AnnotationConfigReactiveWebServerApplicationContext。执行刷新调用经典 Spring 的refresh方法完成 Bean 的创建、依赖注入、初始化等过程。执行 Runner容器刷新完毕后依次执行ApplicationRunner和CommandLineRunner接口的实现类。启动完成后执行初始化逻辑的示例javaComponent public class DataInitRunner implements CommandLineRunner { Override public void run(String... args) throws Exception { System.out.println(容器启动完成执行数据初始化...); } }四、配置文件与多环境管理4.1 配置文件格式Spring Boot 支持application.properties和application.yml。YAML 层级清晰适合复杂配置properties 更简单直观。yamlserver: port: 8080 servlet: context-path: /api spring: application: name: demo-service datasource: url: jdbc:mysql://localhost:3306/demo username: root password: 1234564.2 多环境配置使用application-{profile}.yml区分环境并在主配置中激活yaml# application.yml spring: profiles: active: devyaml# application-dev.yml server: port: 8081 spring: datasource: url: jdbc:mysql://localhost:3306/dev_db也可以在启动命令中动态指定bashjava -jar app.jar --spring.profiles.activeprod4.3 配置属性优先级从高到低大致如下命令行参数Java 系统属性操作系统环境变量jar 包外部的application-{profile}.ymljar 包内部的application-{profile}.ymljar 包外部的application.ymljar 包内部的application.ymlPropertySource引入的配置默认配置面试提示至少记住“命令行参数优先级最高其次环境变量然后是外部配置文件最后是内部配置文件”这条主线。4.4 配置绑定使用ConfigurationProperties将配置项批量绑定到实体类比逐个使用Value更清晰javaComponent ConfigurationProperties(prefix app.upload) public class UploadProperties { private String path; private long maxSize; private ListString allowTypes; // getter / setter 省略 }yamlapp: upload: path: /data/upload max-size: 10485760 allow-types: - jpg - png - pdf五、常用注解详解5.1 核心组件类注解注解作用Component通用组件将类交给 Spring 容器管理Service业务层组件语义上是 Component 的特化Repository数据访问层组件额外支持异常翻译Controller控制层组件处理 Web 请求RestController等于 Controller 加 ResponseBody返回 JSON 数据Configuration标记配置类内部 Bean 方法会被代理增强Bean在配置类中声明 Bean方法名默认作为 Bean 名称Scope指定 Bean 作用域如 singleton、prototypeLazy延迟初始化 Bean5.2 依赖注入类注解注解说明AutowiredSpring 提供默认按类型注入可结合 Qualifier 按名称注入ResourceJDK 提供默认按名称注入找不到名称再按类型注入Qualifier配合 Autowired 指定注入 Bean 名称Value注入简单属性值支持 SpEL 表达式Autowired 与 Resource 的区别来源不同Autowired 来自 Spring 框架Resource 来自 JDK 的 javax.annotation 包。注入顺序不同Autowired 默认按类型注入Resource 默认按名称注入。配合方式不同Autowired 配合 Qualifier 使用Resource 通过 name 属性指定。是否强制不同Autowired 支持 requiredfalseResource 没有此参数但其行为类似默认必须找到。5.3 Web 相关注解注解作用RequestMapping类或方法级别的请求映射可指定路径、方法、参数等GetMapping/PostMapping/PutMapping/DeleteMapping对应 HTTP 方法的具体映射PathVariable从 URL 路径中获取参数如 /user/{id}RequestParam从请求查询参数或表单中获取参数RequestBody将请求体 JSON 反序列化为对象ResponseBody将方法返回值序列化为 JSON 写回响应RequestHeader读取请求头信息CookieValue获取 Cookie 中指定名称的值SessionAttribute获取 HttpSession 中保存的属性ModelAttribute将请求参数绑定到模型对象常用于表单回显和公共数据初始化ExceptionHandler处理 Controller 中抛出的指定异常ControllerAdvice/RestControllerAdvice全局异常处理、全局数据绑定和全局模型增强ResponseStatus指定响应状态码可配合自定义异常返回对应 HTTP 状态Valid/Validated开启参数校验Valid 是标准 JSR-303Validated 是 Spring 扩展支持分组校验六、参数校验与全局异常处理6.1 参数校验常用注解注解说明NotNull不能为 nullNotBlank字符串不能为 null 且去除首尾空格后长度大于 0NotEmpty字符串、集合或数组不能为 null 且长度或大小大于 0Size(min, max)校验字符串、集合或数组的长度范围Min(value)数值必须大于或等于指定值Max(value)数值必须小于或等于指定值Email校验邮箱格式Pattern(regexp)按正则表达式校验字符串在 DTO 上添加校验注解并在 Controller 方法参数前使用Valid开启校验javapublic class UserCreateRequest { NotBlank(message 用户名不能为空) private String username; Email(message 邮箱格式不正确) private String email; Size(min 6, max 20, message 密码长度必须在 6 到 20 之间) private String password; // getter / setter 省略 } RestController RequestMapping(/users) public class UserController { PostMapping public ResultLong create(Valid RequestBody UserCreateRequest request) { // 校验通过后执行业务逻辑 return Result.success(userService.create(request)); } }6.2 全局异常处理使用RestControllerAdvice配合ExceptionHandler实现全局统一异常处理javaRestControllerAdvice public class GlobalExceptionHandler { ExceptionHandler(MethodArgumentNotValidException.class) public ResultVoid handleValidException(MethodArgumentNotValidException e) { String message e.getBindingResult().getFieldErrors() .stream() .map(FieldError::getDefaultMessage) .collect(Collectors.joining(; )); return Result.fail(400, message); } ExceptionHandler(BusinessException.class) public ResultVoid handleBusinessException(BusinessException e) { return Result.fail(e.getCode(), e.getMessage()); } ExceptionHandler(Exception.class) public ResultVoid handleException(Exception e) { log.error(系统异常, e); return Result.fail(500, 系统繁忙请稍后再试); } }面试中经常被追问的几点参数校验异常需要放在最后兜底、自定义异常要区分业务错误码、不要直接把异常堆栈返回给客户端。七、拦截器、过滤器与监听器7.1 过滤器 Filter过滤器属于 Servlet 规范作用于请求进入 Servlet 容器之后、到达 Controller 之前以及响应返回客户端之前。javaComponent public class RequestTimeFilter implements Filter { Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { long start System.currentTimeMillis(); chain.doFilter(request, response); long cost System.currentTimeMillis() - start; System.out.println(请求耗时 cost ms); } }7.2 拦截器 HandlerInterceptor拦截器属于 Spring MVC 体系依赖 Spring 容器常用于权限校验、登录检查、接口统计等javaComponent public class AuthInterceptor implements HandlerInterceptor { Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token request.getHeader(Authorization); if (!StringUtils.hasText(token)) { throw new BusinessException(401, 未登录); } return true; } } Configuration public class WebConfig implements WebMvcConfigurer { private final AuthInterceptor authInterceptor; public WebConfig(AuthInterceptor authInterceptor) { this.authInterceptor authInterceptor; } Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(authInterceptor) .addPathPatterns(/api/**) .excludePathPatterns(/api/login, /api/register); } }7.3 过滤器与拦截器的区别对比项过滤器 Filter拦截器 HandlerInterceptor所属规范Servlet 规范Spring MVC 框架依赖容器Servlet 容器Spring 容器触发时机进入 DispatcherServlet 之前进入 Controller 方法之前应用场景编码、跨域、日志等通用处理登录校验、权限校验等业务处理7.4 监听器监听器可以监听 Servlet 容器生命周期事件和 Spring 容器事件。常问ApplicationRunner与CommandLineRunner的区别两者都在应用启动完成后执行ApplicationRunner参数是ApplicationArgumentsCommandLineRunner参数是原始字符串数组。javaComponent public class ApplicationReadyListener { EventListener(ApplicationReadyEvent.class) public void onReady() { System.out.println(应用已就绪); } }八、事务管理8.1 Transactional 核心属性propagation事务传播行为默认 REQUIRED。isolation事务隔离级别默认使用数据库默认隔离级别。readOnly只读事务适合查询方法。rollbackFor指定哪些异常触发回滚默认只有 RuntimeException 和 Error 回滚。timeout事务超时时间。javaTransactional(rollbackFor Exception.class, timeout 30) public void createOrder(OrderCreateRequest request) { // 业务代码 }8.2 事务传播行为传播行为含义REQUIRED有事务则加入没有则新建事务最常见REQUIRES_NEW总是新建事务并挂起当前事务SUPPORTS有事务则加入没有则以非事务方式执行NOT_SUPPORTED总是以非事务方式执行并挂起当前事务MANDATORY必须在事务中执行否则抛异常NEVER必须以非事务方式执行否则抛异常NESTED嵌套事务内层事务可以独立回滚面试常问「REQUIRED 和 REQUIRES_NEW 的区别」REQUIRED 跟随外部事务一起提交或回滚REQUIRES_NEW 独立开启新事务内层方法提交后不受外层回滚影响。8.3 事务失效常见场景自调用同一个类内部方法直接调用没有经过代理对象。方法不是 publicTransactional 只对 public 方法生效。异常被捕获方法内捕获并吞噬异常框架感知不到异常不会回滚。rollbackFor 不匹配抛出受检异常但未配置 rollbackFor。数据源或事务管理器不匹配多数据源场景下没有指定正确的事务管理器。不被 Spring 管理类没有注册为 Bean或是在非 Spring 线程中调用。九、缓存使用9.1 缓存注解常用注解包括Cacheable、CachePut、CacheEvict和Caching。javaCacheable(cacheNames user, key #id) public User getUserById(Long id) { return userMapper.selectById(id); } CachePut(cacheNames user, key #user.id) public User updateUser(User user) { userMapper.updateById(user); return user; } CacheEvict(cacheNames user, key #id) public void deleteUser(Long id) { userMapper.deleteById(id); }Cacheable会在方法执行前先查缓存命中则直接返回。CachePut始终执行方法并更新缓存。CacheEvict执行方法后删除缓存。9.2 缓存穿透、击穿、雪崩问题含义常见解决思路缓存穿透请求不存在的数据每次都绕过缓存直接打到数据库缓存空值、布隆过滤器、参数校验缓存击穿热点 key 过期瞬间大量请求同时访问数据库热点不过期、互斥锁重建缓存缓存雪崩大量 key 同一时间过期或缓存服务不可用随机过期时间、本地缓存兜底、多级缓存回答时要区分三者的定义、触发条件和应对措施。十、日志框架Spring Boot 默认使用 SLF4J 作为日志门面并引入 Logback 作为默认实现。使用日志门面的好处在于业务代码不直接依赖具体日志实现后续可无感切换。javaSlf4j RestController public class LogDemoController { GetMapping(/log) public String logDemo() { log.info(info 级别日志{}, 示例参数); return ok; } }在application.yml中可通过logging.level、logging.file.name等属性配置日志级别和输出文件。十一、总结Spring Boot 的核心可以浓缩为以下几句话定位Spring Boot 不是 Spring 的替代而是在 Spring 之上的快速开发脚手架。三大能力起步依赖解决依赖管理自动配置解决配置繁琐内嵌容器解决部署复杂。自动配置入口是EnableAutoConfiguration→AutoConfigurationImportSelector→SpringFactoriesLoader通过Conditional系列注解按需生效。启动流程SpringApplication.run→ 准备环境 → 创建上下文 → refresh → 执行 Runner。配置管理多环境 profile、外部化配置优先级、ConfigurationProperties批量绑定。Web 开发注解体系、参数校验、全局异常处理、Filter/Interceptor/Listener 三者区别。数据与缓存声明式事务、事务失效场景、缓存三大问题与应对。
返回列表