【Spring】面试突击系列(六):Spring 工程实践与面试综合

Spring 工程实践与面试综合:6 期系列收官之作

本文是 "Spring 全家桶源码级深度解析" 系列的第 6 期(最终期),融合工程化规范、线上排查实战、30 道综合面试题和 EduLearn 完整复盘。

前 5 期回顾:第1期 IoC/DI | 第2期 自动配置 | 第3期 Spring MVC | 第4期 AOP 深度解析| 第5期 事务


目录

  • 开篇:代码跑通了,但能上线吗?
  • [一、EduLearn 工程化规范](#一、EduLearn 工程化规范)
    • [1.1 分层架构:四层分离,单向依赖](#1.1 分层架构:四层分离,单向依赖)
    • [1.2 统一返回体:ApiResponse](#1.2 统一返回体:ApiResponse)
    • [1.3 全局异常处理:@ControllerAdvice](#1.3 全局异常处理:@ControllerAdvice)
    • [1.4 参数校验:@Valid + JSR 303](#1.4 参数校验:@Valid + JSR 303)
    • [1.5 日志规范](#1.5 日志规范)
    • [1.6 配置管理:application.yml 环境隔离](#1.6 配置管理:application.yml 环境隔离)
  • 二、线上问题排查实战
    • [2.1 OOM / 内存泄漏](#2.1 OOM / 内存泄漏)
    • [2.2 CPU 飙升 100%](#2.2 CPU 飙升 100%)
    • [2.3 死锁](#2.3 死锁)
    • [2.4 慢 SQL](#2.4 慢 SQL)
    • [2.5 接口响应慢](#2.5 接口响应慢)
    • [2.6 连接池耗尽](#2.6 连接池耗尽)
  • [三、EduLearn 完整复盘](#三、EduLearn 完整复盘)
    • [3.1 模块串联示例:用户下单全流程](#3.1 模块串联示例:用户下单全流程)
  • [四、30 道 Spring 综合面试题库](#四、30 道 Spring 综合面试题库)
  • [五、6 期系列总览](#五、6 期系列总览)

开篇:代码跑通了,但能上线吗?

前面 5 期,我们从 IoC 容器一路写到事务源码,用 EduLearn 在线教育平台串联了所有技术点。但写完代码只是起点------上线后才是真正的考验。

凌晨 3 点,CPU 突然飙到 100%;用户投诉下单后迟迟没反应;运维说内存一周涨了 2G......这些不是面试题,是真实的生产事故。

本期作为收官之作,不谈单个技术原理,而是把 5 期知识串成一个可落地的工程体系:分层架构怎么搭、异常怎么统一处理、问题怎么排查、面试怎么回答。


一、EduLearn 工程化规范

1.1 分层架构:四层分离,单向依赖

复制代码
Controller  →  Service  →  DAO/Mapper  →  DB
   ↓              ↓            ↓
统一返回体    事务管理     MyBatis XML
参数校验      AOP横切      PageHelper
全局异常

铁律:上层依赖下层,下层绝不反向依赖上层。Service 不能引入 Controller 包,Mapper 不能引入 Service 包。

1.2 统一返回体:ApiResponse

没有统一返回体的 API 是灾难------每个接口返回格式不同,前端需要写 N 套解析逻辑。

java 复制代码
@Data
@NoArgsConstructor
@AllArgsConstructor
public class ApiResponse<T> {
    private int code;        // 业务状态码
    private String message;  // 提示信息
    private T data;          // 响应数据
    private long timestamp;  // 时间戳

    public static <T> ApiResponse<T> success(T data) {
        return new ApiResponse<>(200, "success", data, System.currentTimeMillis());
    }

    public static <T> ApiResponse<T> error(int code, String message) {
        return new ApiResponse<>(code, message, null, System.currentTimeMillis());
    }
}

Controller 层只返回 ApiResponse

java 复制代码
@GetMapping("/courses/{id}")
public ApiResponse<CourseVO> getCourse(@PathVariable Long id) {
    return ApiResponse.success(courseService.getById(id));
}

1.3 全局异常处理:@ControllerAdvice

不要在每个 Controller 里写 try-catch------用 @ControllerAdvice 一刀切。

java 复制代码
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResponse<?> handleValidation(MethodArgumentNotValidException ex) {
        String msg = ex.getBindingResult().getFieldErrors().stream()
                .map(e -> e.getField() + ": " + e.getDefaultMessage())
                .collect(Collectors.joining("; "));
        return ApiResponse.error(400, "参数校验失败: " + msg);
    }

    @ExceptionHandler(BusinessException.class)
    public ApiResponse<?> handleBusiness(BusinessException ex) {
        return ApiResponse.error(ex.getCode(), ex.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ApiResponse<?> handleUnknown(Exception ex) {
        log.error("未知异常", ex);
        return ApiResponse.error(500, "服务器内部错误");
    }
}

自定义业务异常

java 复制代码
public class BusinessException extends RuntimeException {
    private final int code;
    public BusinessException(int code, String message) {
        super(message);
        this.code = code;
    }
    public int getCode() { return code; }
}

这样 Service 层只需 throw new BusinessException(10001, "库存不足"),Controller 层零 try-catch。

1.4 参数校验:@Valid + JSR 303

java 复制代码
@PostMapping("/orders")
public ApiResponse<OrderVO> createOrder(@Valid @RequestBody OrderDTO dto) {
    return ApiResponse.success(orderService.create(dto));
}

@Data
public class OrderDTO {
    @NotNull(message = "用户ID不能为空")
    private Long userId;

    @NotNull(message = "课程ID不能为空")
    private Long courseId;

    @Min(value = 1, message = "数量至少为1")
    @Max(value = 10, message = "单次最多购买10门")
    private int count;
}

校验失败抛出的 MethodArgumentNotValidExceptionGlobalExceptionHandler 统一捕获,返回格式化错误信息。

1.5 日志规范

yaml 复制代码
logging:
  level:
    root: INFO
    com.edulearn: DEBUG                    # 业务包
    org.springframework.transaction: TRACE # 事务日志(排查用)
    org.springframework.web: DEBUG         # MVC 请求日志
  pattern:
    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n"

日志使用规范

级别 使用场景
ERROR 需要人工介入的异常(支付失败、数据库宕机)
WARN 可自动恢复的异常(重试成功、降级处理)
INFO 关键业务流程(下单、支付、退款)
DEBUG 调试信息(方法入参、SQL 参数、缓存命中)

禁止事项 :① log.info 里调用方法(如 log.info("user: {}", user.toString())------toString 在生产也会执行);② 循环内打 INFO 日志;③ e.printStackTrace()(改用 log.error("msg", e))。

java 复制代码
// 正确
log.info("订单创建成功, orderId={}, userId={}", order.getId(), dto.getUserId());
// 错误
log.info("订单创建成功" + order); // 字符串拼接浪费性能

1.6 配置管理:application.yml 环境隔离

复制代码
application.yml              # 公共配置
application-dev.yml          # 开发环境
application-test.yml         # 测试环境
application-prod.yml         # 生产环境

通过 spring.profiles.active=prod 切换。敏感信息(数据库密码、API Key)不要硬编码,用环境变量或配置中心:

yaml 复制代码
spring:
  datasource:
    password: ${DB_PASSWORD}  # 从环境变量读取

二、线上问题排查实战

2.1 OOM / 内存泄漏

现象 :应用运行几小时后崩溃,java.lang.OutOfMemoryError: Java heap space

排查流程

bash 复制代码
# 1. 找到 Java 进程
jps -lv

# 2. 看堆使用情况
jmap -heap PID

# 3. 查看存活对象 Top 20
jmap -histo:live PID | head -20

# 4. 如果上面看不出,导出堆快照
jmap -dump:format=b,file=heap.hprof PID

用 Eclipse MAT(Memory Analyzer Tool)打开 heap.hprof,查看 Dominator Tree,找到占用内存最大的对象。

经典案例------ThreadLocal 内存泄漏

java 复制代码
// 问题代码
public class RequestContext {
    private static ThreadLocal<User> currentUser = new ThreadLocal<>();
    // 使用后没有 remove() !Tomcat 线程池复用线程 → 线程不消亡 → ThreadLocal 永远不回收
}

// 正确做法
public class RequestContext {
    private static ThreadLocal<User> currentUser = new ThreadLocal<>();
    public static void clear() {
        currentUser.remove(); // 在 Filter/Interceptor 的 afterCompletion 中调用
    }
}

预防 :设置 JVM 参数 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/heapdump.hprof,OOM 时自动 dump。

2.2 CPU 飙升 100%

排查流程

bash 复制代码
# 1. 找到进程内高 CPU 线程
top -Hp PID

# 2. 记录高 CPU 线程的 TID(十进制),转十六进制
printf '%x\n' TID

# 3. 用 jstack 看这个线程在干什么
jstack PID | grep -A 20 十六进制TID

Arthas 一键版(强烈推荐)

bash 复制代码
# 启动 Arthas
java -jar arthas-boot.jar

# 查看最忙的 3 个线程
dashboard

# 直接找当前阻塞其他线程的元凶
thread -b

# 观察方法耗时
trace com.edulearn.service.OrderService createOrder

常见原因

  • 死循环(while(true) 没有 sleep)
  • 正则表达式回溯(如 (a+)+b 匹配长字符串)
  • 频繁 Full GC(堆快满了,GC 线程持续工作 → 看 GC 日志)

2.3 死锁

现象:请求卡住不返回,线程数持续增长。

bash 复制代码
# jstack 直接帮你找到死锁
jstack PID | grep "Found one Java-level deadlock" -A 50

输出会明确指出哪些线程持有哪些锁、等待哪些锁:

复制代码
Found one Java-level deadlock:
==============================
"Thread-1":
  waiting to lock monitor 0x00007f8a1c001a58 (object 0x000000076abcf1d0, a java.lang.Object),
  which is held by "Thread-0"
"Thread-0":
  waiting to lock monitor 0x00007f8a1c003f58 (object 0x000000076abcf1e0, a java.lang.Object),
  which is held by "Thread-1"

Arthas 版thread -b 直接输出死锁链。

根因与预防

  • 统一加锁顺序(所有地方先锁 A 再锁 B)
  • 减小锁粒度(不要锁整个方法,只锁关键代码块)
  • ReentrantLock.tryLock(timeout, unit) 替代 synchronized

2.4 慢 SQL

bash 复制代码
# 1. 找到正在执行的慢查询
SHOW FULL PROCESSLIST;

# 2. 启用慢查询日志
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;  -- 超过 1 秒记录

# 3. 分析执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 123 AND status = 'PAID';

EXPLAIN 关键字段

字段 含义 理想值
type 访问类型 const > ref > range > index > ALL
key 使用的索引 非空
rows 扫描行数 越小越好
Extra 额外信息 避免 Using filesort / Using temporary

常见慢 SQL 优化

  • 缺少索引 → CREATE INDEX idx_user_status ON orders(user_id, status)
  • SELECT * → 只查需要的列
  • LIMIT 100000, 20 深分页 → 改用游标分页(WHERE id > lastId LIMIT 20
  • JOIN 字段类型不一致(隐式转换导致全表扫描)
  • 未利用覆盖索引 → EXPLAIN 看 Extra 是否是 Using index

2.5 接口响应慢

先用 SkyWalking / Pinpoint 等 APM 工具定位到具体接口,再用 Arthas trace:

bash 复制代码
arthas> trace com.edulearn.controller.OrderController createOrder -n 5

输出完整的调用链和每一层的耗时,一眼看出瓶颈在 Service、DAO 还是第三方调用。

2.6 连接池耗尽

bash 复制代码
# 连接池配置(HikariCP 默认)
spring.datasource.hikari.maximum-pool-size=20
spring.datasource.hikari.connection-timeout=30000

如果日志出现 Connection is not available, request timed out after 30000ms,排查:

  • 是否有连接泄漏(获取连接后没关,可用 jstack 查看线程是否 BLOCKED 在 getConnection
  • 最大连接数是否太小
  • 是否有慢 SQL 长时间持有连接

三、EduLearn 完整复盘

6 期系列贯穿的 EduLearn 在线教育平台,最终架构如下:

模块 核心功能 用到的主要技术
用户模块 注册登录、JWT认证、角色权限、手机验证码 IoC(MVC注入)、MVC(RESTful Controller)、AOP(日志切面)、Spring Security
课程模块 CRUD、ES搜索、分类标签、Redis缓存 IoC(Bean管理)、自动配置(ES Starter)、MVC(分页查询)
订单模块 下单、支付回调、退款、库存扣减 事务(核心)、AOP(日志)、MVC(RESTful)
学习模块 课程进度、笔记、视频播放、作业提交 MVC(文件上传)、自动配置(OSS Starter)
消息模块 站内信、推送通知、RabbitMQ异步 事务(REQUIRES_NEW)、消息队列

技术栈全貌

复制代码
Spring Boot 2.7.x          # 基础框架
├── Spring IoC/DI          # 第1期:Bean生命周期、依赖注入、自动装配
├── Spring Boot 自动配置    # 第2期:Starter机制、条件注解、配置绑定
├── Spring MVC             # 第3期:DispatcherServlet、拦截器、RESTful
├── Spring AOP             # 第4期:动态代理、切面编程、通知顺序
├── Spring 事务             # 第5期:@Transactional、传播行为、失效场景
├── Spring Security + JWT  # 认证与授权
├── MyBatis / MyBatis-Plus # 数据访问层
├── Redis + Spring Cache   # 缓存
├── Elasticsearch          # 全文搜索
├── RabbitMQ               # 消息队列
└── Actuator + Prometheus  # 监控

3.1 模块串联示例:用户下单全流程

这是整个系统最复杂的业务流程,串联了 5 个模块的技术点:

复制代码
1. [用户模块] JWT 解析用户身份 → SecurityContext
2. [Controller] @Valid 校验 OrderDTO 参数 → 统一异常处理兜底
3. [AOP] @LogAspect 记录接口调用日志
4. [Service - 事务] @Transactional 开启事务
   ├── [课程模块] 查询课程信息 + Redis 缓存预热
   ├── [订单模块] 创建订单记录 → MyBatis insert
   ├── [课程模块] 扣减库存 → REQUIRED 加入当前事务
   ├── [订单模块] 扣减余额 → MANDATORY 要求事务存在
   └── [消息模块] 发送通知 → REQUIRES_NEW 独立事务
5. [事务] commit → 数据落地;rollback → 全部回滚
6. [AOP] @LogAspect 记录耗时和结果
7. [Controller] 返回 ApiResponse<OrderVO>

四、30 道 Spring 综合面试题库

覆盖 6 期内容,按模块分类。

IoC / DI(第1期)

Q1 :Spring IoC 容器的启动流程?

Anew AnnotationConfigApplicationContext(Config.class) → 注册配置类 → refresh()invokeBeanFactoryPostProcessors 解析 @ComponentScan@BeanfinishBeanFactoryInitialization 实例化所有单例 Bean。全部单例 Bean 在容器启动时创建(非懒加载),通过三级缓存解决循环依赖。

Q2@Autowired@Resource 的区别?

A@Autowired 是 Spring 注解,默认按类型注入,配合 @Qualifier 按名称;@Resource 是 JSR-250 标准,默认按名称,找不到再按类型。@Autowired 可标记 required=false

Q3 :Spring 如何解决循环依赖?

A :三级缓存。一级 singletonObjects(成品)、二级 earlySingletonObjects(半成品)、三级 singletonFactories(ObjectFactory)。A 创建时提前暴露 ObjectFactory 到三级缓存 → B 创建时依赖 A,从三级缓存获取 A 的早期引用 → B 创建完成 → A 继续完成创建。

Q4@Configuration@Component 的区别?

A@Configuration 标注的类会被 CGLIB 增强,@Bean 方法内部调用其他 @Bean 方法时返回的是容器中的同一个实例(单例保证)。@Component 没有这个增强,内部调用 @Bean 方法会创建新对象。

Q5FactoryBeanBeanFactory 的区别?

ABeanFactory 是 IoC 容器的顶层接口(工厂的工厂)。FactoryBean 是生产特定类型 Bean 的工厂,常用于框架集成(如 SqlSessionFactoryBean 生产 SqlSession)。

自动配置(第2期)

Q6@SpringBootApplication 包含哪三个注解?

A@SpringBootConfiguration(= @Configuration)、@EnableAutoConfiguration(自动配置核心)、@ComponentScan(组件扫描)。

Q7 :自动配置的实现原理?

A@EnableAutoConfiguration@Import(AutoConfigurationImportSelector.class) → 读取 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports → 加载所有自动配置类 → 每个配置类用 @ConditionalOnClass@ConditionalOnMissingBean 等条件注解判断是否生效。

Q8 :如何自定义一个 Starter?

A :① 创建 xxx-spring-boot-autoconfigure 模块,写自动配置类用 @ConditionalOnClass 控制生效条件;② 创建 xxx-spring-boot-starter 模块(空项目,引入 autoconfigure 模块);③ 在 autoconfigure 的 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中声明配置类全限定名。

Spring MVC(第3期)

Q9 :DispatcherServlet 的处理流程?

A :请求 → HandlerMapping 找到 Handler(Controller 方法)→ HandlerAdapter 执行 → HandlerMethodArgumentResolver 解析参数(@RequestBody / @RequestParam 等)→ 执行 Controller 方法 → HttpMessageConverter 序列化返回值 → 返回响应。中途经过 HandlerInterceptorpreHandle / postHandle / afterCompletion

Q10 :拦截器(Interceptor)和过滤器(Filter)的区别?

A:Filter 是 Servlet 规范,在请求进入 Servlet 前执行,不感知 Spring 上下文;Interceptor 是 Spring 机制,在 HandlerMapping 之后、Controller 执行前后执行,能拿到 HandlerMethod 和 Spring Bean。Filter 在最外层,Interceptor 在 DispatcherServlet 内部。

Q11@RequestBody@ResponseBody 的工作原理?

A :通过 HttpMessageConverter 做序列化/反序列化。Spring Boot 默认使用 Jackson(MappingJackson2HttpMessageConverter)处理 JSON。@RequestBody 在参数解析阶段调用 read() 反序列化;@ResponseBody 在返回值处理阶段调用 write() 序列化。

AOP(第4期)

Q12 :JDK 动态代理和 CGLIB 的区别,Spring 如何选择?

A :JDK 基于接口 + Proxy.newProxyInstance + InvocationHandler,目标类必须实现接口;CGLIB 基于继承 + Enhancer + MethodInterceptor,通过生成子类覆写方法实现。Spring Boot 2.x 默认用 CGLIB。如果目标类实现了接口,也可以显式设置 spring.aop.proxy-target-class=false 来用 JDK 代理。

Q13 :同一个切面中多个通知的执行顺序?

A@Around start → @Before → 目标方法 → @AfterReturning / @AfterThrowing@After@Around end。@After 无论异常都会执行(类似 finally),@AfterReturning 只在正常返回时执行。

Q14 :多切面作用在同一方法时,执行顺序如何控制?

A :通过 @Order(n) 控制,数值越小优先级越高。@Around 是嵌套结构------外层切面的 Around 包裹内层切面的 Around,最后才到目标方法。

事务(第5期)

Q15@Transactional 失效的常见场景(至少说 3 个)?

A :① 自调用(this.method() 不经过代理);② 方法非 public;③ 异常被 try-catch 吞掉;④ Checked Exception 默认不回滚,需 rollbackFor = Exception.class;⑤ 多线程/@Async 场景(ThreadLocal 线程隔离)。

Q16 :7 种传播行为,至少说 3 个常用的?

AREQUIRED(默认,同生共死)、REQUIRES_NEW(独立事务,挂起外部)、NESTED(保存点,部分回滚)。前两者高频,NESTED 依赖 JDBC savepoint。

Q17REQUIREDREQUIRES_NEW 的本质区别?

AREQUIRED 加入外部事务,共用同一个 Connection,同一批操作同生共死。REQUIRES_NEW 挂起外部连接,从 DataSource 获取新连接,开启独立事务------子事务的提交/回滚完全不影响外部。

Q18 :事务怎么做到线程隔离的?为什么多线程会失效?

ATransactionSynchronizationManagerThreadLocal<Map<Object, Object>> 存储当前线程的 DataSource→Connection 映射。新线程拿不到父线程的 ThreadLocal 数据,自然不在同一事务中。

工程实践(第6期)

Q19 :你们项目的分层架构是怎样的?

A:Controller → Service → DAO/Mapper → DB。Controller 负责参数校验和统一返回,Service 负责业务逻辑和事务管理,DAO 负责数据访问。横切关注点(日志、异常、权限)通过 AOP 和全局异常处理统一管理。

Q20 :线上 CPU 飙升,你的排查步骤?

Atop -Hp PID 找到高 CPU 线程 → printf '%x' TID 转十六进制 → jstack PID | grep 十六进制 定位代码 → 或者 Arthas thread -n 3 一键看最忙线程。常见原因:死循环、正则回溯、频繁 Full GC。

Q21 :线上内存泄漏怎么排查?

Ajmap -histo:live PID | head -20 看存活对象分布;如果不明显,jmap -dump 导出堆快照,MAT 的 Dominator Tree 分析最大占用。注意 ThreadLocal 没 remove 导致的内存泄漏------tomcat 线程池复用导致线程不消亡。

Q22 :慢 SQL 排查流程?

ASHOW FULL PROCESSLIST 看正在执行的 SQL → 启用慢查询日志 long_query_time=1EXPLAIN 分析执行计划,关注 type(避免 ALL)、key(必须有索引)、rows(越小越好)、Extra(避免 filesort/temporary)→ 加索引、优化 JOIN、避免 SELECT *

Q23 :全局异常处理怎么做?

A@RestControllerAdvice + @ExceptionHandler。自定义 BusinessException(code, message),各层统一 throw,由全局处理器转为 ApiResponse.error() 返回。Controller 层零 try-catch。

Q24 :Spring Security + JWT 的认证流程?

A :登录接口 → 验证用户名密码 → 生成 JWT token(含 userId、角色、过期时间)→ 返回 token。后续请求在 Header 带 Authorization: Bearer token → JWT 过滤器解析 token → 验证签名和过期时间 → 将用户信息放入 SecurityContext。

Q25 :Redis 在你们项目中的使用场景?

A :① 课程详情缓存(@Cacheable,TTL 30分钟);② 分布式锁(SETNX,下单防超卖);③ 用户 session 存储(JWT 黑名单);④ 排行榜(ZSet,按学习时长排序)。

综合追问链

Q26 :从浏览器输入 URL 到 Spring Boot 返回 JSON,中间经过哪些层?

A:Nginx 反向代理 → Tomcat 线程池接收 → Filter Chain → DispatcherServlet → HandlerMapping → HandlerInterceptor.preHandle → Controller 方法(参数解析 + 校验)→ Service(事务、缓存、AOP)→ DAO → DB → 返回值序列化(Jackson)→ HandlerInterceptor.postHandle/afterCompletion → Response。

Q27 :Spring 中 Bean 的生命周期?

A :实例化 → 属性填充(依赖注入)→ BeanNameAware / BeanFactoryAwareBeanPostProcessor.postProcessBeforeInitialization@PostConstruct / InitializingBean.afterPropertiesSetBeanPostProcessor.postProcessAfterInitialization(AOP 代理在此生成)→ 就绪 → 容器关闭时 @PreDestroy / DisposableBean.destroy

Q28 :Spring Boot 如何实现 "约定优于配置"?

A:通过自动配置机制。Spring Boot 预设了合理的默认值(如 HikariCP 默认最大连接数 10,Tomcat 默认端口 8080),开发者只需在 application.yml 中覆盖需要的配置项。这种"默认即最佳实践"的理念大大减少了 XML 配置和样板代码。

Q29 :你对 Spring 6 / Spring Boot 3.x 的升级了解吗?

A :最大变化是基线升级到 JDK 17 和 Jakarta EE 9(javax.*jakarta.*)。AOT 编译和 GraalVM Native Image 支持是性能亮点。此外 spring.factories 改为 AutoConfiguration.imports 文件格式。如果你的项目还在 JDK 8/11,升级时需要处理包名变更和弃用 API。

Q30 :如果让你从零搭建一个 Spring Boot 项目,你的技术选型清单?

A:Spring Boot 3.x + JDK 17 + MySQL 8.x + MyBatis-Plus + Redis + RabbitMQ + JWT + Actuator + Prometheus + Grafana。分层:Controller → Service → DAO。横切:全局异常处理 + AOP 日志 + 统一返回体。测试:JUnit 5 + Mockito。CI/CD:GitLab CI + Docker + K8s。


五、6 期系列总览

期数 主题 核心知识点
第1期 IoC / DI 容器启动流程、Bean生命周期、三级缓存、循环依赖
第2期 自动配置 Starter机制、条件注解、配置绑定、自定义Starter
第3期 Spring MVC DispatcherServlet、拦截器vs过滤器、RESTful、参数解析
第4期 AOP JDK vs CGLIB、切面通知顺序、@Order源码走读
第5期 事务 7种传播行为、5大失效场景、TransactionInterceptor源码
第6期 工程综合 分层架构、异常处理、排查实战、30道面试题、项目复盘

学习路线建议:按顺序阅读,第1-3期打基础,第4-5期攻源码,第6期做串联和面试冲刺。

相关推荐
摇滚侠2 小时前
JavaWeb 全套教程 乱码问题 85-88
java·开发语言
问心无愧05132 小时前
ctf show web入门102
android·java·前端·笔记
San813_LDD2 小时前
[量化]《虚函数调用时间复杂度完全解析:为什么是 O(1) 以及它的真实代价》
java·数据结构·算法
武子康2 小时前
Java-19 深入浅出MyBatis 代理模式:从 Java 动态代理到 Mapper 接口的底层原理
java·后端
devilnumber2 小时前
Java Lambda方法引用的三类核心类型、转化逻辑与深度对比
java·开发语言
郑洁文2 小时前
基于Springboot的足球青训俱乐部管理系统的设计与实现
java·spring boot·后端·足球青训俱乐部管理系统
牛油果子哥q2 小时前
【C++ this指针】C++ this指针深度精讲:this底层本质、存储位置、调用机制、const this指针、空指针调用、面试坑点与工程实战
开发语言·c++·面试
云烟成雨TD2 小时前
Spring AI 1.x 系列【39】MCP Java SDK 与 Spring AI 集成
java·人工智能·spring
极客先躯2 小时前
高级java每日一道面试题-2026年01月19日-实战篇[Docker]-如何配置镜像仓库的垃圾回收 (GC)?
java·运维·docker·容器