韩国是“Spring共和国”吗?
如果你想在韩国以后端开发者的身份找到工作,有一个问题几乎无法回避:“你会用 Spring 吗?”
打开招聘网站,十家公司里有九家都会在要求里明确写上“有 Spring Boot 经验”。夸张到甚至有了“Spring共和国”这种说法。大学时期的我,一直以为这只是潮流而已。
“直接用 Java 写不就行了吗,为什么非要用这么重的 Spring?”“Node.js 或 Python(Django)不是更简单吗?”
但真正进入实务、经历过大型项目之后,我才明白:Spring 不是单纯的流行,而是一套为了让庞大而复杂的企业系统能够“安全而快速”地构建起来,被无数前辈开发者不断打磨出的标准工作台。
这一系列,讲的就是如何在这张标准工作台上,搭建一座不会轻易倒塌的城堡,也就是 Monolith。
框架:为什么不能完全按自己的意思来
在正式进入技术细节之前,有一件事必须先说清楚。到底什么是框架(Framework)?它和库(Library)又有什么区别?
我在前面的 Re: Booting 系列里提到过一点,但这两者最关键的区别,其实在于“到底是谁掌握主导权”。
Spring 是框架。所以说“使用 Spring”,几乎就等于在发誓:“我愿意先放下自己的编码习惯,按照 Spring 的方式来。”而这种“按它说的做”的核心,正是今天要讲的控制反转(IoC)。
“拜托,别再老是写 new 了”
这份誓约的第一条规则就很震撼:不要使用 Java 最基础不过的 new 运算符。
大学时,如果我需要一个对象,理所当然就会写 MemberService service = new MemberService();。我需要什么,就自己创建出来再用。这不是再正常不过了吗?
可入职后我打开 Spring Boot 项目时,代码里怎么找都看不到 new。取而代之的是 @Autowired、@RequiredArgsConstructor 这类陌生的注解。
“不是,对象都没创建,方法到底怎么调用?这玩意儿真的能跑?”
我问前辈开发者时,得到的回答听起来有点云里雾里:“Spring Container 会自己给你注入(Inject),所以不用自己创建。反而如果你老是直接写 new,以后维护起来会很痛苦。”
我当时完全不能理解。代码是我写的,为什么连创建一个对象都不能自己说了算?那种感觉,简直像是Spring 的独裁。

厨师与食材经理(IoC & DI)
为了理解这种看似“独裁”的规则为什么必要,我们把世界观切换成“餐厅厨房”。
1. 传统方式(我说了算)
我是厨师,也就是一个 Class。要做菜,我需要一把刀,也就是 Dependency。
2. Spring 的方式(Spring 说了算)
我还是那个厨师。但这一次,厨房里多了一个“食材经理(Spring Container)”。
也就是说,我不再自己管理我所需要的资源,而是交给外部的管理者来统一管理,再由他交到我手上。这就是控制反转(IoC: Inversion of Control),而它的具体实现方式,就是依赖注入(DI)。

[Code Verification] 为什么 new 很危险
光靠嘴说很难真正有感觉。我们直接用代码来对比。假设我们要做一个“信用卡支付系统”。
1. 坏例子:直接创建(强耦合)
public class PaymentService {
// 我直接選擇並建立了「三星卡」(使用 new)
private final SamsungCard card = new SamsungCard();
public void pay() {
card.payment(); // 只能用三星卡付款
}
}
问题点:某天老板突然说:“我们换成手续费更低的 现代卡 吧!”那我就得打开 PaymentService 的代码,把所有 SamsungCard 全部改成 HyundaiCard。如果这样的代码散落在 100 个地方呢?那就准备加班吧。
2. 好例子:依赖注入(松耦合)
public class PaymentService {
private final Card card; // 不指定具體發卡公司(使用介面)
// 建構子注入:相信「外面會有人把卡交給我」
public PaymentService(Card card) {
this.card = card;
}
public void pay() {
card.payment();
}
}
这样一来,PaymentService 就不再关心传进来的到底是哪一种卡实现了。
这就是实务里常说的“更容易维护的代码(OCP 原则)”的核心。之所以使用 Spring Boot,正是因为这种灵活性。
Spring Container:对象们的酒店
那么,这个负责创建对象并把它们交出来的“经理”,到底是谁?答案就是 Spring Container。
当我们启动 Spring Boot 服务器、执行 run 的那一刻,内部其实会发生很多事情。
我们真正要做的,只不过是在类上贴一张“请帮我管理这个”的标签,比如 @Service。剩下的事,就交给 Spring 这个巨大的酒店经理去处理。
实务建议:使用构造器注入
在 Spring 中,依赖注入有很多方式:@Autowired 字段注入、Setter 注入、构造器注入。但在实务里,几乎都会推荐“构造器注入”。(也就是常和 Lombok 的 @RequiredArgsConstructor 一起使用的那种方式。)
@Service
@RequiredArgsConstructor // 這就是自動產生建構子注入的關鍵
public class OrderService {
// 可以加 final,所以很安全
private final PaymentService paymentService;
}
原因:
结语:不是魔法师,而是指挥家
一开始,我很抗拒 Spring,因为它看起来像是在随意摆布我的代码。但现在我明白了。Spring 不是折磨我的独裁者,而是一个帮我梳理复杂对象关系的优秀指挥家。
正因如此,我花在“到底要创建什么对象”上的时间变少了,可以把更多精力放在“如何用这些对象写好业务逻辑”上。这大概就是为什么韩国开发者会如此偏爱 Spring。
好了,现在我们已经把对象管理的权限交给了 Spring,服务器也准备启动了。但 Web 应用并不是自己单独运行的,它还必须和界面,也就是 Frontend 对话。PHP 时代,HTML 和代码混在一个文件里确实很方便;可为什么现在要把 Frontend(Vue、React)和 Backend 分开开发?而且为什么把两边一接起来,就会冒出红色的 CORS 错误?
下一篇,我们就来拆开看看 Web 架构的变化,SSR vs CSR,以及横在它们之间的 CORS 到底是什么。