首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

MVC 架構漸進式掌握(二):Action 接口與工廠模式實現業務邏輯解耦

     編輯:Java 相關知識

從 Servlet 到 MVC:為什麼需要 Action 接口?

在傳統 Servlet 開發中,業務邏輯、請求處理、視圖跳轉往往混雜在 doGet/doPost 方法中,導致代碼難以復用與維護。MVC 模式的核心在於「關注點分離」:Model 處理數據與業務,View 負責展示,Controller 協調流程。本文介紹的 Action 接口與 ActionFactory 正是 Controller 層解耦的關鍵實現。

Action 接口:統一業務處理契約

package actions;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface Action {
    /**
     * 執行具體業務邏輯
     * @param servlet  當前 Servlet 實例,提供訪問 ServletConfig/Context 的能力
     * @param req      HTTP 請求對象
     * @param res      HTTP 響應對象
     * @return ActionRouter 路由對象,封裝轉發/重定向邏輯
     * @throws IOException, ServletException
     */
    public ActionRouter perform(HttpServlet servlet,
                                HttpServletRequest req,
                                HttpServletResponse res)
            throws java.io.IOException, javax.servlet.ServletException;
}

設計亮點:

  • 接口隔離:具體業務類(如 LoginAction, OrderAction)只需實現 perform 方法,無需繼承特定基類。
  • 依賴注入雛形:通過參數傳入 servlet, req, res,避免了對 Servlet API 的硬編碼依賴,便於單元測試。
  • 返回路由對象:ActionRouter 封裝了視圖跳轉邏輯(轉發/重定向/鏈式調用),實現了「業務邏輯不關心具體視圖路徑」。

ActionFactory:單例緩存與動態加載

package actions;

import java.util.Hashtable;

public class ActionFactory {
    private Hashtable actions = new Hashtable();

    public Action getAction(String classname, ClassLoader loader)
            throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        
        // 1. 嘗試從緩存獲取
        Action action = (Action) actions.get(classname);
        
        // 2. 緩存未命中,動態加載並實例化
        if (action == null) {
            Class klass = loader.loadClass(classname);  // 載入 Class 對象
            action = (Action) klass.newInstance();      // 調用無參構造器創建實例
            actions.put(classname, action);             // 存入緩存
        }
        
        return action;
    }
}

核心機制深度解析

1. Java 反射機制:Class.forName() vs ClassLoader.loadClass()

  • Class.forName(className):載入並初始化類(執行 static 靜態代碼塊)。適用於需要觸發驅動註冊(如 JDBC Driver)的場景。
  • ClassLoader.loadClass(className):僅載入類到 JVM 元空間,不初始化(不執行 static 塊)。工廠模式中使用此方法可避免重複初始化副作用,性能更優。

2. Class.newInstance() 的限制與替代

klass.newInstance() 僅能調用 公共無參構造器,且拋出檢查型異常 (InstantiationException, IllegalAccessException)。

現代替代方案 (Java 9+):

// 推薦:使用 Constructor 對象,支持私有構造器、參數傳遞、異常鏈
Constructor<Action> ctor = klass.getDeclaredConstructor();
ctor.setAccessible(true); // 允許訪問私有構造器
Action action = ctor.newInstance();

3. ClassLoader 雙親委派模型與 Web 應用隔離

代碼中傳入的 getClass().getClassLoader() 通常返回 AppClassLoader (系統類加載器) 或 Web 容器的 WebAppClassLoader。

  • Bootstrap ClassLoader:加載核心庫 (rt.jar 等)。
  • Extension ClassLoader:加載擴展庫 (jre/lib/ext)。
  • AppClassLoader / WebAppClassLoader:加載應用類路徑 (WEB-INF/classes, WEB-INF/lib)。

委派鏈:子類加載器先委派父加載器查找,找不到再自行加載。這保證了核心類不被應用覆蓋,也實現了 Web 應用間的類隔離(同一容器不同 WebApp 可加載同名不同版本的類)。

動態加載類的實戰價值

  • 熱部署/熱加載:修改 Action 實現類後,無需重啟容器,工廠可通過自定義 ClassLoader 重新加載新版本字節碼。
  • 插件化架構:新增業務模塊只需放入 JAR 包並配置類名,無需修改框架代碼。
  • 多租戶隔離:不同租戶使用獨立 ClassLoader 加載各自的 Action 實現,數據邏輯物理隔離。

總結

Action 接口定義了「做什麼」,ActionFactory 解決了「怎麼獲取做事的對象」。這雙劍合璧,構成了早期 MVC 框架(如 Struts 1.x 核心思想)Controller 層的基石。理解其背後的反射機制與類加載原理,對掌握現代框架(Spring MVC Controller, Servlet 3.0+ 動態註冊)的內部運作極有裨益。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved