《Spring Boot 应用开发》高分心得:12 条工程化法则 + 最小可交付样例(含 Docker/CI 模板)

Spring Boot 工程化法则与最小样例

摘要:系统复盘课程要点,给出分层设计、统一异常、校验、事务、测试金字塔、容器化、CI/CD、监控告警的落地方法。附最小可交付示例与排错清单。
适用人群:Java 后端入门到进阶、课设与实战项目。
关键词:Spring Boot、分层架构、校验、全局异常、事务、单元测试、集成测试、Docker、GitHub Actions、Actuator、Micrometer
 

目录

  • 一、课程价值回看

  • 二、工程化 12 条硬规则

  • 三、最小可交付样例(Task 服务)

  • 四、排错清单与性能定位

  • 五、监控与可观测最小闭环

  • 六、团队协作与代码规范

  • 七、课程作业提分打法

  • 八、常见问题 FAQ

  • 九、参考与延伸

  • 十、总结与可复用模板

建议先赞藏,实操时对照 Checklist。


一、课程价值回看:学会交付而不是堆注解

  • 目标不是“跑起来”,而是**“稳定交付”**。

  • 交付的三件套:清晰分层 + 自动化测试 + 一键部署


二、工程化 12 条硬规则(可直接采纳)

1)分层架构(适配/领域/基础设施)


Controller(协议适配) → Service(用例规则/事务) → Repository(存储细节)

  • Controller 只做 DTO 与协议转换;业务只进 Service。

2)配置分环境与密钥外置

application.yml + application-<profile>.yml;敏感信息走环境变量或密钥服务。

3)参数校验与统一错误返回

  • jakarta.validation + @Valid

  • @RestControllerAdvice 产出一致 JSON。


@RestControllerAdvice class GlobalExHandler { @ExceptionHandler(MethodArgumentNotValidException.class) ResponseEntity<Map<String,Object>> badReq(MethodArgumentNotValidException e){ var errors=e.getBindingResult().getFieldErrors().stream() .collect(Collectors.toMap(FieldError::getField, DefaultMessageSourceResolvable::getDefaultMessage,(a,b)->a)); return ResponseEntity.badRequest().body(Map.of("code","VALIDATION_ERROR","errors",errors)); } }

4)事务边界只放 Service

  • 读多写少加 @Transactional(readOnly = true)

  • 避免同类内自调用导致事务失效。

5)日志为排障服务

  • 统一字段:traceId/userId/costMs;输出 JSON。

  • 约束 error 级别,避免告警风暴。

6)测试金字塔

  • 单测多、集成适量、端到端少量且关键路径必测。

  • @WebMvcTest 切片测控制器,@SpringBootTest + Testcontainers 测集成。

7)API 文档代码生成

  • springdoc-openapi 生成 Swagger UI,CI 中校验可用性。

8)安全默认收紧

  • Spring Security 启用后显式放行匿名端点。

  • CORS 用 CorsConfigurationSource 定源、定方法。

9)性能优化的顺序

  • 先度量后优化:线程池、慢查询、GC → 再考虑缓存/异步。

  • 缓存只加纯查询路径,失效策略先定后上。

10)容器化交付

极简 Dockerfile:


FROM eclipse-temurin:21-jre WORKDIR /app COPY build/libs/app-*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java","-XX:+UseContainerSupport","-jar","/app/app.jar"]

11)CI/CD 最小闭环

  • Push→Test→Build Jar→Build Image。

  • 失败即退回,镜像带 commit sha。

12)可观测默认打开

  • spring-boot-starter-actuator + Micrometer。

  • 指标、健康检查、日志聚合一个都不少。


三、最小可交付样例:待办任务 Task 服务

3.1 目录结构建议


src/main/java/com/example/app ├─ api // Controller + DTO ├─ domain // 领域模型与规则 ├─ application// 用例服务(与domain可合并) ├─ infra // Repository/Client └─ config // 安全/跨域/Bean

3.2 领域与接口

  • 实体:Task(id, title, description, status, createdAt)

  • 接口:

    • POST /api/tasks 创建

    • GET /api/tasks/{id} 查询

    • PATCH /api/tasks/{id}/done 完成

3.3 Controller(含校验)


@RestController @RequestMapping("/api/tasks") @RequiredArgsConstructor class TaskController { private final TaskService service; record CreateCmd(@NotBlank String title, String description) {} record TaskVO(Long id,String title,String description,String status,Instant createdAt){} @PostMapping ResponseEntity<TaskVO> create(@Valid @RequestBody CreateCmd cmd){ return ResponseEntity.status(HttpStatus.CREATED).body(service.create(cmd)); } @GetMapping("/{id}") TaskVO find(@PathVariable Long id){ return service.find(id); } @PatchMapping("/{id}/done") TaskVO done(@PathVariable Long id){ return service.done(id); } }

3.4 Service(事务与规则)


@Service @RequiredArgsConstructor class TaskService { private final TaskRepository repo; @Transactional TaskController.TaskVO create(TaskController.CreateCmd cmd){ var t=new Task(cmd.title(), cmd.description()); repo.save(t); return TaskController.TaskVOMapper.from(t); } @Transactional(readOnly = true) TaskController.TaskVO find(Long id){ return TaskController.TaskVOMapper.from(repo.get(id)); } @Transactional TaskController.TaskVO done(Long id){ var t=repo.get(id); if(t.isDone()) throw new BizException("TASK_ALREADY_DONE"); t.markDone(); return TaskController.TaskVOMapper.from(t); } }

3.5 统一异常


class BizException extends RuntimeException{ BizException(String c){ super(c); } }

3.6 数据表(PostgreSQL 示例)


create table task( id bigint primary key generated always as identity, title varchar(200) not null, description text, status varchar(16) not null default 'NEW', created_at timestamp not null default now() );

3.7 Web 层切片测试


@WebMvcTest(TaskController.class) class TaskControllerTest { @Autowired MockMvc mvc; @MockBean TaskService service; @Test void create_ok() throws Exception { when(service.create(any())).thenReturn(new TaskVO(1L,"t","d","NEW",Instant.now())); mvc.perform(post("/api/tasks").contentType(APPLICATION_JSON) .content("""{"title":"t","description":"d"}""")) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id").value(1)); } }

3.8 Docker 一键跑


docker build -t task-app:latest . docker run -p 8080:8080 --env-file .env task-app:latest


四、排错清单与性能定位(对分项)

场景典型原因快速定位
自动配置未生效条件缺失/actuator/conditions
事务不生效自调用或非 public打开代理日志,重构调用
校验不触发@ValidController 入参核对
N+1 查询懒加载列表DTO 投影或 fetch join
CORS 失败预检未放行允许 OPTIONS 与头部
日志爆量频繁 error等级收敛 + 采样
时区错乱序列化混用统一 ISO-8601 + Instant

五、监控与可观测最小闭环

  • 指标:http.server.requests、线程池活跃、JVM 内存、GC。

  • 健康:/actuator/health,数据库、消息队列、外部依赖。

  • 日志:结构化 JSON,关联 traceId,落到日志平台。


六、团队协作与代码规范

  • 统一格式化与静态检查:Spotless、Checkstyle、Error Prone。

  • 约定提交信息与分支模型:feat/fix/docs/refactor/test

  • PR 模板内置检查项:测试通过、Swagger 可用、变更记录。


七、课程作业提分打法(助攻 98+)

  1. README 展示:架构图(可用 Mermaid)、启动步骤、接口列表。

  2. 截图三件套:Swagger 页面、测试报告、容器运行日志。

  3. 贴上 Checklist 与排错记录,体现工程意识。

  4. 监控面板最小化图一张(请求量与 P95 耗时)。

  5. CI 成功记录截图一张。

图示占位:

  • 架构图(思维导图/时序图/部署图)

  • Swagger 截图

  • GitHub Actions 成功勾


八、常见问题 FAQ

Q:必须用 JPA 吗?
A:不强制。MyBatis-Plus 也行。关键是分层与事务边界清晰。

Q:为什么要写那么多测试?
A:测试是可维护的成本下限。没有测试,改一次慌一次。

Q:容器化对课设有必要吗?
A:是加分项。助教一键跑得起来,就赢一半。


九、参考与延伸(官方优先)

  • Spring Boot、Spring Data、Spring Security 官方文档

  • Spring Guides 场景手册

  • Micrometer、Actuator、OpenAPI 3 规范

  • 《Clean Architecture》《Domain-Driven Design Quickly》


十、总结与可复用模板

  • 一句话:以交付为目标组织项目,其余环节全部服务于可维护、可测试、可发布。

  • 模板清单

    • GlobalExHandler.java

    • CorsConfig.java

    • Dockerfile

    • ci.yml

    • README.md(启动步骤 + 截图位)


发布到 优快云 的操作要点(直接照做)

  • 标题含主关键词与数字法则:已满足。

  • 添加标签Spring Boot后端开发测试容器化CI/CD可观测性

  • 封面图:工程架构/Swagger 截图,清晰不带水印。

  • 文章内3–5 张图:架构图、Swagger、CI 成功记录、监控面板。

  • 开启目录原创新声明,加入系列专栏

  • 末尾 CTA:引导收藏、评论区提问与关注专栏。

  • 代码块高亮,段落 2–4 行一组,表格 + Checklist 提升可读性。

这版就是给分机器爱看的结构:关键词、图文并茂、可复用代码、可验证闭环。去发。

您说:

现在是90分,你觉得有什么改进的吗?

ChatGPT 说:

已思考 9s

结论:还能抬到 95–98。优先做“机器分+读者留存”两条线。按优先级给你可直接粘贴的增补块。

P0|最提分的改动(先做这5件)

  1. 首屏三要素

  • 换标题:《Spring Boot 应用开发》高分心得:12条工程化法则 + 最小可交付样例(含Docker/CI模板)

  • 开头 3 行放“摘要、要点、代码仓库占位链接”。

  • 系列专栏站内相关文章内链3处(优快云偏好站内流转)。

  1. 结构化图示(Mermaid,站内可渲染)
    粘贴到“目录”上方,拉阅读时长与完读率:


flowchart LR A[Controller/DTO] --> B[Service/Use Case] B --> C[(Repository/DB)] B --> D[Domain Rules] A --> E[Global Exception] subgraph Platform F[Actuator/Micrometer] --> G[Prometheus/Grafana] H[OpenAPI] --> A end

  1. 一键运行块(可复制即用)


# docker-compose.yml(贴图示和说明) services: db: image: postgres:16 environment: { POSTGRES_PASSWORD: dev, POSTGRES_DB: app } ports: ["5432:5432"] app: image: ghcr.io/owner/demo-app:latest environment: DB_URL: jdbc:postgresql://db:5432/app DB_USER: postgres DB_PASS: dev ports: ["8080:8080"] depends_on: [db] # 启动 docker compose up -d

  1. 测试+Swagger 截图位

  • 放 3 张图:Swagger、CI 通过、/actuator/health。

  • 图下各写一句话说明与关键指标(P95/成功率)。

  1. 末尾 CTA 强化与互动问题

  • 设 3 个问题引导评论:

    • 你们团队事务边界如何划?

    • Actuator 暴露了哪些自定义指标?

    • 失败重试与幂等等价替代怎么选?

P1|机器权重项(SEO/原创/排版)

  • 关键词密度:在小标题里重复“Spring Boot、统一异常、事务、测试、Docker、CI/CD、Actuator”。

  • 标签Spring Boot后端单元测试DockerCI/CDMicrometerActuatorSwagger

  • 目录+分段:每段 2–4 行,代码块与表格穿插。

  • 原创声明+系列:加“本篇为课程总结与工程化实践,后续『Spring Boot 工程化实战』连载”。

P2|内容强化块(直接贴)

统一错误返回对照表

维度低分做法高分做法
校验仅注解注解+分层校验(DTO/Domain)
返回文本信息规范 JSON:code/message/traceId
可观测记录 path/method/status/costMs

CORS 最小安全配置


@Bean CorsConfigurationSource cors(){ var c=new CorsConfiguration(); c.setAllowedOrigins(List.of("https://your-frontend.example")); c.setAllowedMethods(List.of("GET","POST","PATCH")); c.setAllowedHeaders(List.of("Content-Type","Authorization")); var s=new UrlBasedCorsConfigurationSource(); s.registerCorsConfiguration("/**", c); return s; }

CI 徽章与检查项(README 顶部)


![CI](https://img.shields.io/badge/CI-passing-brightgreen) - 必过:单测、OpenAPI 可访问、镜像构建成功

性能排查顺序清单(贴成Checklist)

  • 打开 Actuator 指标与日志采样

  • 线程池/连接池可视化

  • 慢查询 ≥ 200ms 列表

  • 垃圾回收停顿 < 100ms@P95

  • 再考虑缓存/异步/批处理

FAQ 增补三问

  • Q:@Transactional 自调用为何失效?
    A:AOP 代理绕过。抽出到独立 bean 或通过接口调用。

  • Q:Swagger 在生产如何收敛?
    A:仅在 dev/staging 开启,生产反向代理白名单。

  • Q:Testcontainers 太慢?
    A:使用复用容器,或本地开发以 H2/禁部分集成测权衡。

P3|站内权重与回访机制

  • 在开头放“版本号与更新记录”:v1.1 更新:新增 Mermaid 架构图、Docker Compose、一键运行指南、FAQ 3 条。

  • 文章末尾挂“下一篇预告”:【下一篇】Spring Boot + Testcontainers 持续集成最佳实践

  • 在正文中部插入站内相关文章3个超链(自己的或精选):校验、事务、Actuator。


一次到位的“变更包”(按位插入)

  • 标题、摘要、Mermaid 图、Docker Compose、对照表、Checklist、FAQ、CTA、版本记录、系列链接。

  • 配 3–5 张无水印截图。

  • 关键词+标签统一。

做完 P0+P1 基本能到 95;补上 P2 的对照表与 FAQ,图片齐备,稳定 97–98。

您说:

你把那些我该做的事情去掉,给我一个完整的可复制的

ChatGPT 说:

《Spring Boot 应用开发》高分心得:12 条工程化法则 + 最小可交付样例(含 Docker/CI 模板)

摘要:复盘课程要点。落地分层设计、统一异常、校验、事务、测试金字塔、容器化、CI/CD、可观测。附“Task 服务”最小可交付样例与排错清单。
版本:v1.1(新增 Mermaid 架构图、Docker Compose、一键运行、FAQ 增补)
关键词:Spring Boot、统一异常、事务、测试、Docker、CI/CD、Actuator、Swagger、Micrometer


目录

  • 一、课程价值

  • 二、12 条工程化法则

  • 三、最小可交付样例(Task 服务)

  • 四、排错清单与性能定位

  • 五、可观测闭环

  • 六、团队协作与规范

  • 七、作业提分展示面板

  • 八、FAQ

  • 九、参考

  • 十、总结


一、课程价值

目标不是“能跑”。目标是稳定交付
核心三件套:清晰分层 + 自动化测试 + 一键部署


二、12 条工程化法则

1)分层架构


Controller(协议适配) → Service(用例与事务) → Repository(存储细节)

2)配置分环境与密钥外置

application.yml + application-<profile>.yml;敏感信息走环境变量。

3)参数校验与统一错误

jakarta.validation + @Valid@RestControllerAdvice 产出一致 JSON。

4)事务边界在 Service

读多写少标 @Transactional(readOnly = true);避免同类自调用。

5)日志为排障服务

结构化 JSON;字段包含 traceId/userId/costMs;控制 error 级别。

6)测试金字塔

单测多、集成适量、端到端少量但关键路径必测。

7)API 文档代码生成

springdoc-openapi 生成 Swagger;CI 校验可访问。

8)安全默认收紧

Spring Security 显式放行匿名端点;CORS 精确配置来源与方法。

9)性能优化顺序

先度量再优化:线程池、慢查询、GC → 缓存/异步/批处理。

10)容器化交付

精简 JRE 镜像;分层缓存;环境变量驱动。

11)CI/CD 最小闭环

Push→Test→Build Jar→Build Image。镜像打上 commit sha。

12)可观测默认打开

Actuator + Micrometer;指标、健康、日志统一。


架构示意(Mermaid)


flowchart LR A[Controller/DTO] --> B[Service/Use Case] B --> C[(Repository/DB)] B --> D[Domain Rules] A --> E[Global Exception] subgraph Platform F[Actuator/Micrometer] --> G[Prometheus/Grafana] H[OpenAPI/Swagger] --> A I[CI/CD] --> A end


三、最小可交付样例:Task 服务

3.1 目录结构


src/main/java/com/example/app ├─ api // Controller + DTO ├─ domain // 领域模型与规则 ├─ application// 用例服务 ├─ infra // Repository/Client └─ config // 安全/跨域/Bean

3.2 统一异常处理


package com.example.app.config; import org.springframework.context.support.DefaultMessageSourceResolvable; import org.springframework.http.*; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.*; import java.util.*; import java.util.stream.Collectors; @RestControllerAdvice public class GlobalExHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<Map<String, Object>> badReq(MethodArgumentNotValidException e) { var errors = e.getBindingResult().getFieldErrors().stream() .collect(Collectors.toMap(FieldError::getField, DefaultMessageSourceResolvable::getDefaultMessage, (a,b)->a)); return ResponseEntity.badRequest().body(Map.of( "code", "VALIDATION_ERROR", "errors", errors )); } @ExceptionHandler(BizException.class) public ResponseEntity<Map<String, Object>> biz(BizException e) { return ResponseEntity.status(HttpStatus.CONFLICT).body(Map.of( "code", e.getMessage() )); } @ExceptionHandler(Exception.class) public ResponseEntity<Map<String, Object>> others(Exception e) { return ResponseEntity.internalServerError().body(Map.of( "code","INTERNAL_ERROR","message","请联系管理员" )); } } class BizException extends RuntimeException{ public BizException(String code){ super(code); } }

3.3 Controller(校验 + VO)


package com.example.app.api; import jakarta.validation.constraints.NotBlank; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.*; import org.springframework.web.bind.annotation.*; import java.time.Instant; @RestController @RequestMapping("/api/tasks") @RequiredArgsConstructor public class TaskController { private final TaskService service; public record CreateCmd(@NotBlank String title, String description) {} public record TaskVO(Long id, String title, String description, String status, Instant createdAt){} @PostMapping public ResponseEntity<TaskVO> create(@Valid @RequestBody CreateCmd cmd){ return ResponseEntity.status(HttpStatus.CREATED).body(service.create(cmd)); } @GetMapping("/{id}") public TaskVO find(@PathVariable Long id){ return service.find(id); } @PatchMapping("/{id}/done") public TaskVO done(@PathVariable Long id){ return service.done(id); } }

3.4 Service(事务与规则)


package com.example.app.application; import com.example.app.api.TaskController.TaskVO; import com.example.app.api.TaskController.CreateCmd; import com.example.app.config.BizException; import com.example.app.domain.Task; import com.example.app.infra.TaskRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.time.Instant; @Service @RequiredArgsConstructor public class TaskService { private final TaskRepository repo; @Transactional public TaskVO create(CreateCmd cmd){ var t = new Task(null, cmd.title(), cmd.description(), "NEW", Instant.now()); var saved = repo.save(t); return toVO(saved); } @Transactional(readOnly = true) public TaskVO find(Long id){ return toVO(repo.get(id)); } @Transactional public TaskVO done(Long id){ var t = repo.get(id); if("DONE".equals(t.status())) throw new BizException("TASK_ALREADY_DONE"); var done = t.withStatus("DONE"); return toVO(repo.save(done)); } private TaskVO toVO(Task t){ return new TaskVO(t.id(), t.title(), t.description(), t.status(), t.createdAt()); } }

3.5 领域与 Repository


package com.example.app.domain; import java.time.Instant; public record Task(Long id, String title, String description, String status, Instant createdAt){ public Task withStatus(String s){ return new Task(id, title, description, s, createdAt); } }


package com.example.app.infra; import com.example.app.domain.Task; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import lombok.RequiredArgsConstructor; import java.sql.ResultSet; import java.time.Instant; @Repository @RequiredArgsConstructor public class TaskRepository { private final JdbcTemplate jdbc; public Task save(Task t){ if(t.id()==null){ var id = jdbc.queryForObject( "insert into task(title,description,status,created_at) values (?,?,?,now()) returning id", Long.class, t.title(), t.description(), t.status()); return new Task(id, t.title(), t.description(), t.status(), Instant.now()); } jdbc.update("update task set title=?,description=?,status=? where id=?", t.title(), t.description(), t.status(), t.id()); return t; } public Task get(Long id){ return jdbc.queryForObject("select id,title,description,status,created_at from task where id=?", (ResultSet rs, int row)-> new Task( rs.getLong("id"), rs.getString("title"), rs.getString("description"), rs.getString("status"), rs.getTimestamp("created_at").toInstant() ), id); } }

3.6 数据表(PostgreSQL)


create table if not exists task( id bigint primary key generated always as identity, title varchar(200) not null, description text, status varchar(16) not null default 'NEW', created_at timestamp not null default now() );

3.7 Web 层切片测试


package com.example.app.api; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.web.servlet.MockMvc; import java.time.Instant; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import static org.springframework.http.MediaType.APPLICATION_JSON; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @WebMvcTest(TaskController.class) class TaskControllerTest { @Autowired MockMvc mvc; @MockBean TaskService service; @Test void create_ok() throws Exception { when(service.create(any())).thenReturn(new TaskController.TaskVO(1L,"t","d","NEW", Instant.now())); mvc.perform(post("/api/tasks").contentType(APPLICATION_JSON) .content("{\"title\":\"t\",\"description\":\"d\"}")) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id").value(1)); } }

3.8 Dockerfile(JDK 21)


FROM eclipse-temurin:21-jre WORKDIR /app COPY build/libs/app-*.jar app.jar EXPOSE 8080 ENTRYPOINT ["java","-XX:+UseContainerSupport","-jar","/app/app.jar"]

3.9 一键运行(docker-compose)


services: db: image: postgres:16 environment: POSTGRES_PASSWORD: dev POSTGRES_DB: app ports: ["5432:5432"] app: image: ghcr.io/owner/demo-app:latest environment: DB_URL: jdbc:postgresql://db:5432/app DB_USER: postgres DB_PASS: dev ports: ["8080:8080"] depends_on: [db]

3.10 CI(GitHub Actions)


name: ci on: [push, pull_request] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-java@v4 with: { distribution: 'temurin', java-version: '21' } - name: Test run: ./gradlew test - name: Build Jar run: ./gradlew bootJar - name: Build Image run: docker build -t ghcr.io/owner/demo-app:${{ github.sha }} .


四、排错清单与性能定位

场景典型原因快速定位
自动配置未生效条件缺失/actuator/conditions
事务不生效自调用或非 public代理日志;抽出到独立 bean
校验不触发@ValidController 入参核对
N+1 查询懒加载列表DTO 投影或 fetch join
CORS 失败预检未放行允许 OPTIONS 与所需头
日志爆量频繁 error等级收敛 + 采样
时区错乱序列化混用统一 ISO-8601 + Instant

五、可观测闭环

  • Actuator/actuator/health/actuator/metrics/actuator/info

  • Micrometer 指标http.server.requests、JVM 内存、GC、线程池。

  • 日志关联:输出 traceId,与指标打通。


六、团队协作与规范

  • 格式化与静态检查:Spotless、Checkstyle、Error Prone。

  • 提交信息与分支模型feat/fix/docs/refactor/test

  • PR 检查项:测试通过、Swagger 可访问、镜像构建成功。


七、作业提分展示面板

  • 截图三件套:Swagger 页面、CI 成功、/actuator/health

  • 对照表与 Checklist:如下方两块。

统一错误返回对照表

维度基线强化
校验注解注解 + 分层校验
返回文本规范 JSON:code/message/traceId
观测记录 path/method/status/costMs

性能排查 Checklist

  • Actuator 指标与日志采样开启

  • 线程池/连接池可视化

  • 慢查询 ≥ 200ms 清单

  • GC 停顿 P95 < 100ms

  • 再评估缓存/异步/批处理


八、FAQ

Q1:@Transactional 自调用为何失效?
A:AOP 代理绕过。抽出到独立 bean 或通过接口调用。

Q2:Swagger 在生产如何收敛?
A:仅在 dev/staging 开启;生产通过反向代理白名单。

Q3:Testcontainers 太慢?
A:启用复用容器;本地权衡使用 H2 或减少集成测频次。

Q4:日志如何控量?
A:高频路径降到 info/debug,error 只记录故障;按采样率输出。

Q5:CORS 常见误区?
A:忽略预检;忘记放行 OPTIONS 与必要头;来源写 * 导致凭据失效。


九、参考(官方优先)

  • Spring Boot、Spring Data、Spring Security 文档

  • Spring Guides

  • Micrometer、Actuator、OpenAPI 3 规范

  • 《Clean Architecture》《Domain-Driven Design Quickly》


十、总结

一句话:以交付为目标组织 Spring Boot 项目
工程化让“写对注解”升级为“稳定上线与可维护”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值