什麼是反模式?
反模式 是「典型的糟糕設計」—— 設計模式的對立面。它描述常見、重複、看似合理但最終有害的解決方案。理解反模式與掌握設計模式同等重要:它提供通用詞彙識別問題根源,幫助團隊在維護階段預判風險、避免集體犯錯。J2EE 環境複雜度高,反模式尤為頻發。
通用反模式三大類
設計層面
| 反模式 | 表現 | 後果 | 修正 |
| 具體類而非接口 | 代碼依賴具體實現類 (如 ArrayList list = new ArrayList()),而非接口 (List list = ...) | 難以替換實現、測試時無法 Mock、運行行為被鎖死 | 面向接口編程,構造器/工廠返回接口類型 |
| 過度耦合 | 業務邏輯與日誌、安全、緩存等橫切關注點硬編碼混雜 | 單元測試困難、修改一處牽一髮動全身、復用性極低 | AOP (AspectJ/Spring AOP) 將橫切邏輯織入;或攔截器/過濾器模式 |
開發層面
| 反模式 | 表現 | 修正 |
| 金錘 | 團隊只會一種技術/框架,所有問題強行套用 (如所有項目上 Spring、所有查詢用 Hibernate) | 技術選型失配、過度設計、性能差 | 擴展技術視野,建立技術雷達,按場景選型 |
| 輸入雜亂 | 未驗證/清洗用戶輸入直接進業務邏輯 (如 SQL 注入、XSS、邏輯繞過) | 安全漏洞、數據污染、異常難排查 | 白名單驗證、參數化查詢、輸出編碼、猴子測試/模糊測試 |
架構層面
| 反模式 | 表現 | 修正 |
| 重新發明輪子 | 未調研現有庫/框架/服務,自行實現通用功能 (連接池、日誌、JSON 序列化、任務調度…) | 浪費時間、質量不可控、維護負擔重 | 先調研成熟開源方案,僅在極特殊場景自研 |
| 廠商鎖定 | 核心代碼深度依賴特定廠商 API/特性 (如 WebLogic 專有 JMX、Oracle Hint、特定 EJB 容器擴展) | 遷移成本極高、升級被動、談判議價能力弱 | 隔離層/適配器模式 (如 Commons Logging 對接 Log4J/JUL)、標準 API (JPA、JMS、JTA) |
J2EE 分層反模式詳解
持久層
- 撈網:一次性加載過多關聯數據 (深度查詢),導致內存暴漲、查詢緩慢。
→ 採用分頁/懶加載/圖譜查詢,按需獲取。
- 窒息:未優化數據庫連接池、SQL、網絡帶寬,導致 DB 成瓶頸甚至阻塞整個網絡。
→ 連接池調優、慢 SQL 分析、讀寫分離、緩存熱點數據。
JSP / Servlet
- Session 數據膨脹:將大量業務對象塞入 HttpSession,併發增長導致 OOM、鍵衝突、敏感信息洩漏跨 Session。
→ Session 僅存跨請求工作流必要數據,及時清理,大對象放緩存/數據庫。
- 嵌入導航:JSP 間硬編碼鏈接/跳轉路徑,頁面重命名引發連鎖修改。
→ 集中式路由配置 (Struts struts-config.xml、Spring MVC @RequestMapping、Thymeleaf 片段)。
- Servlet 重復公共代碼:多 Servlet 複製粘貼驗證、日誌、編碼設置等邏輯。
→ Filter 鏈、BaseServlet 模板方法、框架攔截器 (Struts Interceptor、Spring HandlerInterceptor)。
- 細粒度 EJB 遠程調用:Servlet 循環調用多個 EJB getter,每次經歷序列化/反序列化、網絡往返。
→ EJB 提供粗粒度業務接口 (DTO 聚合數據)、或引入本地接口 / 服務層 Facade。
EJB
- 大事務:單事務跨多資源 (多庫、JMS、外部服務) 長時間持有鎖,併發吞吐崩潰。
→ 拆分為多個小事務、補償事務 (Saga)、或將長 DB 操作移入存儲過程。
- JMS 隊列過載:同一隊列混發不同類型消息 (文本、Map、Bytes),消費端需自行判別類型。
→ 不同業務用不同 Queue/Topic,或消息頭攜帶類型標識由路由器分發。
Web Services
- SOA = Web Services:誤以為 SOA 必須用 SOAP/WS-*。
→ SOA 是架構風格 (服務自治、契約優先、鬆耦合),可用 REST、gRPC、消息隊列、甚至本地調用實現。
其他通用 J2EE 反模式
- 硬編碼 JNDI 查找:代碼寫死
new InitialContext().lookup("java:comp/env/jdbc/MyDS"),環境變更需重編譯部署。
→ Spring @Resource / JNDI 模板 外置配置,或單例緩存查找結果並監聽環境變更。
- EJB 容器服務利用不足:自行實現群集、負載均衡、事務管理、安全、容錯,而容器已內建。
→ 深入理解容器能力 (如 @TransactionAttribute、@RolesAllowed、@Asynchronous),業務代碼專注領域邏輯。
總結
反模式不是「禁忌」,而是經驗教訓的結晶。將其命名、分類、建檔,賦予團隊共同語言,使代碼評審、架構評估、故障複盤都能快速定位「熟悉的壞味道」。下次看到 Vector 被當作堆疊、Session 塞入 10MB 對象、DAO 方法裡拼接 SQL 字符串,請大聲說出:「這是 反模式 X,我們有更好的做法。」