「每日構建」、「測試驅動」、「接口設計」——這些是基礎工程規範,非架構決策。本文針對架構師在項目中面臨的關鍵權衡,提煉 6 條來自實戰的深度經驗,每條都關繫系統安全性、可維護性、擴展性的生死存亡。
// 前端 JS 驗證 (可被繞過)
function validate() {
if (username.length > 20) return false;
if (!password.match(/^[a-zA-Z0-9]+$/)) return false;
return true;
}
// 後端 Servlet 盲目信任
String sql = "SELECT * FROM users WHERE username='" + request.getParameter("username")
+ "' AND password='" + request.getParameter("password") + "'";
輸入用戶名:admin'--
生成 SQL:SELECT * FROM users WHERE username='admin'--' AND password='...'
註釋掉密碼檢查,直接以 admin 登錄!
| 維度 | 客戶端驗證 | 服務端驗證 |
|---|---|---|
| 目的 | 用戶體驗 (即時反饋、減少請求) | 系統安全 (數據完整、業務邏輯、防注入) |
| 可信度 | 不可信 (可禁用 JS、偽造請求、自定義客戶端) | 唯一可信邊界 |
| 實現位置 | 瀏覽器/移動端/第三方客戶端 | Controller/Service/DAO/數據庫約束 |
PreparedStatement / ORM 參數綁定,徹底消除 SQL 注入
// JSP 中混雜權限判斷
<% if (user.hasRole("admin")) { %> 管理 <% } %>
// Action 中硬編碼檢查
public String execute() {
if (!SecurityUtil.checkPermission(user, "DELETE_ORDER")) return "denied";
// 刪除訂單...
}
@PreAuthorize("hasRole('ADMIN')") 註解聲明式控制安全必須在項目啟動第一天納入架構設計,而非上線前補丁。業務功能可延期,安全缺陷不可逆。
| 層面 | 具體項目 | 架構影響 |
|---|---|---|
| 文本 | 標籤、提示、錯誤信息、郵件模板 | ResourceBundle / 數據庫多語言表 |
| 格式化 | 日期、時間、數字、貨幣、電話、地址 | Locale 感知的 Formatter 服務 |
| 圖像/媒體 | 含文字圖標、文化敏感顏色/手勢、視頻字幕 | 資源分發策略 (CDN 按 Locale 分目錄) |
| 排版/佈局 | RTL (阿拉伯/希伯來)、字體大小、行高、表單方向 | CSS 邏輯屬性、模板引擎條件渲染 |
| 業務規則 | 驗證規則、稅制、法定節假日、郵編格式 | 可插拔的業務規則引擎 |
| 數據存儲 | 字符集 (UTF-8MB4)、排序規則、全文檢索分詞 | 數據庫遷移腳本、索引重建策略 |
// 錯誤:Action 中直接寫業務邏輯
public class OrderAction extends Action {
public ActionForward execute(...) {
// 100 行:校驗、計價、庫存扣減、下單、發消息...
}
}
正確:Model = Business Delegate / Facade,僅調用服務層,轉發結果給 View。
// 錯誤:Action 為 JSP 準備格式化數據
list.sort(Comparator.comparing(Order::getDate).reversed());
for (Order o : list) o.setFormattedAmount(fmt.format(o.getAmount()));
request.setAttribute("orders", list);
正確:View 層 (JSP/Velocity/Thymeleaf) 使用標籤/工具類格式化,Model 返回原始領域對象。
正確:利用前端控制器 (DispatcherServlet) + 攔截器鏈集中處理:
| 維度 | EJB (早期規範) | POJO + Spring |
|---|---|---|
| 容器依賴 | 強依賴 EJB 容器 (WebLogic/WebSphere/JBoss) | 僅需 Servlet 容器 (Tomcat/Jetty),可獨立運行 |
| 啟動速度 | 慢 (數分鐘) | 快 (秒級) |
| 測試性 | 難單元測試 (需容器) | 純 Java 單元測試,Mock 容易 |
| 事務管理 | 聲明式 (CMT) 強綁定容器 | 聲明式 (@Transactional) + 編程式,無容器綁定 |
| 遷移成本 | 極高 (綁定專有 API/配置) | 極低 (標準 Java EE / Spring API) |
需要分布式事務 (XA) + 遠程調用 (RMI-IIOP) + 容器管理安全/並發
│
├─ 是 → 考慮 EJB 3.x (現代規範已大幅簡化,支持 POJO 風格)
│
└─ 否 → POJO + Spring (95% 企業應用最佳選擇)
// 定義查詢服務接口 (業務語言)
interface OrderQueryService {
OrderSummary findSummaryById(Long orderId);
Page findItems(Long orderId, Pageable page);
List findTopSelling(int days, int limit);
}
// 實現:直接用 JDBC Template / MyBatis / jOOQ
@Repository
class JdbcOrderQueryService implements OrderQueryService {
private final JdbcTemplate jdbc;
public OrderSummary findSummaryById(Long id) {
return jdbc.queryForObject(
"SELECT o.id, o.user_id, o.total, o.status, u.name " +
"FROM orders o JOIN users u ON o.user_id = u.id WHERE o.id = ?",
(rs, rowNum) -> new OrderSummary(...), id);
}
// 其他查詢...
}
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| CRUD 為主、關聯簡單、團隊熟悉 | MyBatis / JdbcTemplate / jOOQ | SQL 可控、調試易、性能穩、無魔法 |
| 複雜領域模型、豐富關聯、需要緩存/延遲加載 | JPA/Hibernate | 對象圖導航、一級/二級緩存、寫入優化 |
| 高性能讀寫分離、CQRS 架構 | 查詢端:MyBatis/jOOQ + Redis 命令端:JPA/事件溯源 | 讀寫模型分離,各自優化 |
| 微服務、多數據源、異構存儲 | Repository 模式 + 多實現 | 接口隔離存儲細節,工廠路由 |
J2EE 不是技術棧,而是指導原則與模式的集合。架構師的價值在於:在合適的時機、合適的位置、選擇合適的技術、遵循核心原則。