難以置信!我用一個(gè) Java 類替換了整個(gè)后端,還真的跑起來了
在軟件開發(fā)領(lǐng)域,我們往往被各種框架、層次化架構(gòu)、復(fù)雜的配置文件包圍。Spring Boot、微服務(wù)、DTO、Mapper、Docker……這些東西很強(qiáng)大,但在某些小項(xiàng)目里,它們帶來的復(fù)雜度可能遠(yuǎn)遠(yuǎn)超過了項(xiàng)目本身。
我曾經(jīng)突然冒出一個(gè)瘋狂的想法:如果只用一個(gè) Java 類,就能實(shí)現(xiàn)一個(gè)完整的后端服務(wù),會(huì)怎么樣?
聽上去像笑話,對(duì)吧?結(jié)果我真的試了一下,意外發(fā)現(xiàn):不僅能跑,而且對(duì)快速驗(yàn)證原型非常好用。 當(dāng)然,這不是鼓勵(lì)大家拋棄架構(gòu),而是一次“去除繁雜、回歸本質(zhì)”的嘗試。正如一句老話說的:“大道至簡(jiǎn)。”
故事的起點(diǎn)
一切從一個(gè)小型的筆記應(yīng)用開始。需求極其簡(jiǎn)單:
- 保存筆記
- 獲取筆記
- 修改筆記
- 刪除筆記
換句話說,就是一個(gè)標(biāo)準(zhǔn)的 CRUD 系統(tǒng)。 按照傳統(tǒng)做法,我會(huì):
- 起一個(gè) Spring Boot 項(xiàng)目
- 定義實(shí)體、DAO、Service、Controller
- 加 DTO、Mapper
- 寫配置文件
- Docker 打包部署
但這對(duì)一個(gè)微型項(xiàng)目來說,顯然是“大炮打蚊子”。于是我自問:
“能不能用一個(gè)類就把這些搞定,而且還能保持一定的可維護(hù)性?”
執(zhí)行計(jì)劃
我設(shè)定了幾個(gè)原則:
- 使用 Java 自帶的 HttpServer(不依賴 Spring Boot)
- 數(shù)據(jù)存儲(chǔ)放內(nèi)存里,用一個(gè) Map 就夠
- 所有邏輯放進(jìn)一個(gè)類,但結(jié)構(gòu)要清晰
- 提供標(biāo)準(zhǔn) RESTful 接口,前端能直接消費(fèi)
目錄結(jié)構(gòu)非常干凈:
/projects/one-class-backend/src/main/java/com/icoderoad/notes/NoteServer.java單類后端實(shí)現(xiàn)
package com.icoderoad.notes;
import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
public class NoteServer {
private static Map<Integer, String> notes = new HashMap<>();
private static int idCounter = 1;
public static void main(String[] args) throws IOException {
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);
server.createContext("/notes", new HttpHandler() {
@Override
public void handle(HttpExchange exchange) throws IOException {
String method = exchange.getRequestMethod();
switch (method) {
case "GET":
handleGet(exchange);
break;
case "POST":
handlePost(exchange);
break;
case "PUT":
handlePut(exchange);
break;
case "DELETE":
handleDelete(exchange);
break;
default:
exchange.sendResponseHeaders(405, -1);
}
}
});
server.setExecutor(null);
server.start();
System.out.println("Server started on port 8080");
}
private static void handleGet(HttpExchange exchange) throws IOException {
String response = notes.entrySet()
.stream()
.map(e -> e.getKey() + ": " + e.getValue())
.collect(Collectors.joining("\n"));
sendResponse(exchange, response);
}
private static void handlePost(HttpExchange exchange) throws IOException {
String body = new String(exchange.getRequestBody().readAllBytes());
notes.put(idCounter++, body);
sendResponse(exchange, "Note added");
}
private static void handlePut(HttpExchange exchange) throws IOException {
String[] parts = new String(exchange.getRequestBody().readAllBytes()).split(":", 2);
int id = Integer.parseInt(parts[0].trim());
String note = parts[1].trim();
if (notes.containsKey(id)) {
notes.put(id, note);
sendResponse(exchange, "Note updated");
} else {
sendResponse(exchange, "Note not found");
}
}
private static void handleDelete(HttpExchange exchange) throws IOException {
String body = new String(exchange.getRequestBody().readAllBytes());
int id = Integer.parseInt(body.trim());
if (notes.remove(id) != null) {
sendResponse(exchange, "Note deleted");
} else {
sendResponse(exchange, "Note not found");
}
}
private static void sendResponse(HttpExchange exchange, String response) throws IOException {
exchange.sendResponseHeaders(200, response.length());
OutputStream os = exchange.getResponseBody();
os.write(response.getBytes());
os.close();
}
}運(yùn)行邏輯解析
內(nèi)置 HTTP 服務(wù)器
HttpServer 來自 com.sun.net.httpserver,無需任何第三方依賴:
HttpServer server = HttpServer.create(new InetSocketAddress(8080), 0);瞬間就能起一個(gè) 8080 端口的 HTTP 服務(wù)。
請(qǐng)求路由
所有 /notes 請(qǐng)求走一個(gè) HttpHandler,再根據(jù) GET/POST/PUT/DELETE 分發(fā)。
內(nèi)存存儲(chǔ)
private static Map<Integer, String> notes = new HashMap<>();每條筆記有一個(gè)自增 ID,完全夠小項(xiàng)目用了。
CRUD 邏輯
- POST → 新增筆記
- GET → 查詢筆記列表
- PUT → 修改筆記內(nèi)容
- DELETE → 刪除指定 ID 的筆記
測(cè)試接口
# 新增筆記
curl -X POST http://localhost:8080/notes -d "買牛奶"
# 獲取所有筆記
curl http://localhost:8080/notes
# 修改筆記
curl -X PUT http://localhost:8080/notes -d "1: 買咖啡"
# 刪除筆記
curl -X DELETE http://localhost:8080/notes -d "1"收獲與不足
優(yōu)點(diǎn):
- 啟動(dòng)極快(100ms 內(nèi))
- 無框架開銷,零依賴
- 部署就是一個(gè) .class 文件
- 非常適合原型開發(fā)
缺點(diǎn):
- 無持久化,重啟數(shù)據(jù)丟失
- 無鑒權(quán),誰(shuí)都能訪問
- 無校驗(yàn),臟數(shù)據(jù)隨便進(jìn)
- 不適合高并發(fā)
潛在改進(jìn)方案
- 引入 SQLite 文件存儲(chǔ)
- 加上基礎(chǔ) Token 鑒權(quán)
- 返回 JSON 格式,而不是純文本
- 增強(qiáng)錯(cuò)誤處理機(jī)制
適用場(chǎng)景
可以用的地方:
- Hackathon 快速原型
- Demo 演示
- 本地小工具
- 教學(xué)/實(shí)驗(yàn)
不推薦的地方:
- 企業(yè)級(jí)系統(tǒng)
- 高流量網(wǎng)站
- 涉及敏感數(shù)據(jù)的場(chǎng)景
經(jīng)驗(yàn)總結(jié)
這次實(shí)驗(yàn)讓我重新認(rèn)識(shí)了 Java:
- 框架固然重要,但 Java 本身就足夠強(qiáng)大
- 小項(xiàng)目過度設(shè)計(jì),往往是浪費(fèi)時(shí)間
- 簡(jiǎn)單起步,再逐步復(fù)雜化,往往比一上來就堆滿技術(shù)更高效
結(jié)語(yǔ)
我不會(huì)真的在生產(chǎn)里上一個(gè)“單類后端”,畢竟架構(gòu)是為了長(zhǎng)遠(yuǎn)穩(wěn)定。但這個(gè)過程提醒我:有時(shí)候最好的解決方案,就是去掉那些不必要的復(fù)雜性。
下次當(dāng)你要做一個(gè)小工具時(shí),別急著起 Spring Boot。 也許,一個(gè) NoteServer.java 就能讓你秒起后端。
今天就講到這里,如果有問題需要咨詢,大家可以直接留言或掃下方二維碼來知識(shí)星球找我,我們會(huì)盡力為你解答。






























