在傳統 Servlet 開發中,業務邏輯、請求處理、視圖跳轉往往混雜在 doGet/doPost 方法中,導致代碼難以復用與維護。MVC 模式的核心在於「關注點分離」:Model 處理數據與業務,View 負責展示,Controller 協調流程。本文介紹的 Action 接口與 ActionFactory 正是 Controller 層解耦的關鍵實現。
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 封裝了視圖跳轉邏輯(轉發/重定向/鏈式調用),實現了「業務邏輯不關心具體視圖路徑」。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;
}
}
Class.forName() vs ClassLoader.loadClass()Class.forName(className):載入並初始化類(執行 static 靜態代碼塊)。適用於需要觸發驅動註冊(如 JDBC Driver)的場景。ClassLoader.loadClass(className):僅載入類到 JVM 元空間,不初始化(不執行 static 塊)。工廠模式中使用此方法可避免重複初始化副作用,性能更優。Class.newInstance() 的限制與替代klass.newInstance() 僅能調用 公共無參構造器,且拋出檢查型異常 (InstantiationException, IllegalAccessException)。
現代替代方案 (Java 9+):
// 推薦:使用 Constructor 對象,支持私有構造器、參數傳遞、異常鏈
Constructor<Action> ctor = klass.getDeclaredConstructor();
ctor.setAccessible(true); // 允許訪問私有構造器
Action action = ctor.newInstance();
代碼中傳入的 getClass().getClassLoader() 通常返回 AppClassLoader (系統類加載器) 或 Web 容器的 WebAppClassLoader。
rt.jar 等)。jre/lib/ext)。WEB-INF/classes, WEB-INF/lib)。委派鏈:子類加載器先委派父加載器查找,找不到再自行加載。這保證了核心類不被應用覆蓋,也實現了 Web 應用間的類隔離(同一容器不同 WebApp 可加載同名不同版本的類)。
Action 接口定義了「做什麼」,ActionFactory 解決了「怎麼獲取做事的對象」。這雙劍合璧,構成了早期 MVC 框架(如 Struts 1.x 核心思想)Controller 層的基石。理解其背後的反射機制與類加載原理,對掌握現代框架(Spring MVC Controller, Servlet 3.0+ 動態註冊)的內部運作極有裨益。