Files
zhuangang/topics/backend/java-spring/01-java-spring-awareness.md

111 lines
4.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
id: backend.java-spring.awareness
title: Java / Spring Boot(了解级):读懂项目结构、IoC 与依赖注入、分层、事务注解和与 Go / Python 的对照
type: lesson
domain: backend
stack: [java-spring]
tags: [Java, Spring Boot, IoC, 依赖注入, 注解, 事务, JPA, MyBatis, 虚拟线程]
level: basic
prerequisites: [backend.go.index]
est_hours: 2
related: [backend.java-spring.scenario.call-java-service, backend.java-spring.interview]
week: [14]
order: 1
---
# Java / Spring Boot(了解级):读懂项目结构、IoC 与依赖注入、分层、事务注解和与 Go / Python 的对照
> 定位:**能读懂、能对接、面试能聊概念**,不作为主线。BOSS直聘 2026-10-23 的调研中,有 AI 应用岗位写了“熟悉 Java / Go / Python 其中之一”,或者团队已有 Java 业务系统需要 Agent 去调用。示例只用 JDK,在 JDK 26(JDK 21+ 即可)上实际运行通过;Spring 代码为示意,未编译。以官方文档为准:https://docs.spring.io/spring-boot/ 。
## 解释说明
### 与你熟悉的技术对照
| 概念 | Java / Spring Boot | Go | Python / FastAPI |
| --- | --- | --- | --- |
| 数据类 | `record` | struct | `dataclass` / Pydantic 模型 |
| 路由 | `@RestController` + `@GetMapping` | Gin 路由 | `@app.get` |
| 依赖注入 | IoC 容器 + 构造器注入 | 手动在 main 中组装 | `Depends` |
| 参数校验 | `@Valid` + Bean Validation | binding 标签 | Pydantic |
| 数据访问 | Spring Data JPA / MyBatis | database/sql、sqlc、GORM | SQLAlchemy |
| 事务 | `@Transactional` | 手动 `tx.Begin/Commit` | `session.begin()` |
| 并发 | 线程池、虚拟线程(JDK 21) | goroutine | asyncio |
| 构建 | Maven / Gradle | go build | uv / pip |
### Spring 的核心概念
- **IoC 容器**:对象(Bean)由容器创建和管理,你声明依赖,容器注入。推荐**构造器注入**(依赖不可变、便于测试)。
- **分层**:Controller(接收请求)→ Service(业务逻辑、事务)→ Repository(数据访问)。
- **自动配置**:Spring Boot 根据依赖和配置自动创建常用组件(数据源、Web 服务器),配置在 `application.yml`。
- **`@Transactional` 的坑**:基于代理实现,同一个类内部方法调用不经过代理,事务不生效;默认只对运行时异常回滚。
- **AI 相关**:Spring AI、LangChain4j 等框架让 Java 项目也能接入大模型(版本变化快,以官方文档为准)。
### 怎么快速读懂一个 Spring Boot 项目
1. 看 `pom.xml` / `build.gradle`:依赖了什么。
2. 找带 `@SpringBootApplication` 的启动类。
3. 看 `application.yml`:数据库、端口、外部服务地址。
4. 从 Controller 顺着调用链读到 Service 和 Repository。
5. 看全局异常处理(`@RestControllerAdvice`)和拦截器 / 过滤器(鉴权)。
## 案例
你负责的 Python Agent 需要调用公司的 Java 订单服务:读懂它的接口定义(Controller 和 DTO)、错误码、鉴权方式、分页规则,把它封装成 Agent 的工具。
## 代码示例
只用 JDK 的对照示例 [examples/java-basics/OrderDemo.java](examples/java-basics/OrderDemo.java)(`java OrderDemo.java` 运行通过):record、接口 + 构造器注入、Optional、Stream 分组汇总、BigDecimal 金额、虚拟线程。
```text
跨租户查询被拒绝: 订单不存在: B001
t1 按状态汇总: {paid=20.00, refunded=5.00}
用 double 计算金额的问题: 0.1 + 0.2 = 0.30000000000000004
1000 个虚拟线程计数结果: 1000
```
对应的 Spring Boot 写法(示意,未编译):
```java
@RestController
@RequestMapping("/orders")
class OrderController {
private final OrderService service;
OrderController(OrderService service) { this.service = service; } // 构造器注入,无需 @Autowired
@GetMapping("/{id}")
OrderDto get(@PathVariable String id, @RequestHeader("X-Tenant-Id") String tenant) {
return OrderDto.from(service.get(tenant, id));
}
}
@Service
class OrderService {
private final OrderRepository repo;
OrderService(OrderRepository repo) { this.repo = repo; }
@Transactional
public void refund(String tenant, String id) { /* 修改订单 + 写退款记录,在一个事务中 */ }
}
@RestControllerAdvice
class GlobalErrors {
@ExceptionHandler(NotFoundException.class)
ResponseEntity<Map<String, String>> notFound(NotFoundException e) {
return ResponseEntity.status(404).body(Map.of("code", "NOT_FOUND", "message", e.getMessage()));
}
}
```
## 易错点
- 金额用 `double`。
- 同类内部调用带 `@Transactional` 的方法,以为事务生效。
- 受检异常被捕获后吞掉,事务没有回滚。
- 在面试中把“了解”说成“精通”:如实说明能读懂并对接,主语言是 Go / Python。
## 面试常问
- 什么是 IoC 和依赖注入?
- `@Transactional` 什么情况下会失效?
- 你不会 Java,如何和 Java 团队协作?