JFinal源碼 分析之 Core包分析
ActionHandler.java
這個類繼承了上面 說的Handler類,首先我們 上 幾個屬性 ,下面幾個 屬性我們 需要 關心哪些東西 呢?首先 是ActionMapping和RenderManager,其中ActionMapping是通過 構造函數 註入進來的。而RenderManager.me其實 只是一個RenderManager的一個實例而已,
private final boolean devMode; private final ActionMapping actionMapping; private static final RenderManager renderManager = RenderManager.me(); private static final Log log = Log.getLog(ActionHandler.class); public ActionHandler(ActionMapping actionMapping, Constants constants) { this.actionMapping = actionMapping; this.devMode = constants.getDevMode(); }
說到RenderManager.me(),不得 不佩服 JFinal裏面的一個 經常看到的東西 ,下面 貼代碼 ,下面的代碼 在 JFinal裏面經常被 復用,他的作用 其實就是創建一個 實例 的單利 ,而且這個實例是 隨著 Tomcat進程啟動的。
private static final RenderManager me = new RenderManager(); private RenderManager() {} public static RenderManager me() { return me; }
下面 我們 來 看看 其中 的核心 方法handle,在了解 這個之前,我 覺得 還是有 必要看看有 哪些地方引用 到了這個ActionHandler,經過查找 ,發現還是這個地方:
Handler actionHandler = new ActionHandler(actionMapping, constants);
那麽 我們的集中點就是 這個actionMapping了,我們 必須知道這裏面 的實體 的結構 ,經過發現,在JFinal.java當中的me()方法中有一個方法 可以初始化。
private void initActionMapping() { actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors()); actionMapping.buildActionMapping(); Config.getRoutes().clear(); }
從上面的代碼 當中,我們 可以 知道 幾個地方 ,ActionMapping肯定是和route和intercertor(攔截器 )相關聯的,我們 進入 ActionMapping的構造函數一探究竟,發現作者已經註釋掉 了 第二個 參數 。
ActionMapping(Routes routes, Interceptors interceptors) { this.routes = routes; // this.interceptors = interceptors; }
我們再來看看 handle方法:
if (target.indexOf(‘.‘) != -1) { return ; } isHandled[0] = true; String[] urlPara = {null}; Action action = actionMapping.getAction(target, urlPara);
首先如果 target包含.的 話 直接 結束,如果通過,把第一個isHandleed的布爾參數設置為 true.下面 我們 來 看看 getAction方法,
Action getAction(String url, String[] urlPara) { Action action = mapping.get(url); if (action != null) { return action; } // -------- int i = url.lastIndexOf(‘/‘); if (i != -1) { action = mapping.get(url.substring(0, i)); urlPara[0] = url.substring(i + 1); } return action; }
我們 再來 看看 mapping這個屬性,其實 從 上面 下面 的代碼我們可以 看書,target-url中可以獲取 這個target的action.
private final Map<String, Action> mapping = new HashMap<String, Action>();
以上的東西的鏈接示例如下所示 ,可以 結合 上面的代碼 ,從 url中 獲得 最後一個斜杠後的參數。也就是 para.
/** * Support four types of url * 1: http://abc.com/controllerKey ---> 00 * 2: http://abc.com/controllerKey/para ---> 01 * 3: http://abc.com/controllerKey/method ---> 10 * 4: http://abc.com/controllerKey/method/para ---> 11 * The controllerKey can also contains "/" * Example: http://abc.com/uvw/xyz/method/para */
然後我們 回到handle方法吧 ,繼續看下面的代碼,如果 Action為 NULL,那麽就返回 404錯誤 。
if (action == null) { if (log.isWarnEnabled()) { String qs = request.getQueryString(); log.warn("404 Action Not Found: " + (qs == null ? target : target + "?" + qs)); } renderManager.getRenderFactory().getErrorRender(404).setContext(request, response).render(); return ; }
然後我們 看下面的代碼 ,從 下面 的代碼我們 得知,controller其實 是由action生成 的,因為我們之前 未分析 過 Controller,我們 現在 只要 理解這是一個 Controller的 Class類就行 了,然後生成 一個 新的實例,就OK了。
Controller controller = action.getControllerClass().newInstance();
然後 我們 再看 下面 的代碼 ,其實這只是 對 當前controller實例進行構造註入。
controller.init(request, response, urlPara[0]);
然後 我們 繼續 看 後面的代碼,這裏 提到 了一個概念,就是devMode,從字面上來說,這是開發模式 ,我們 暫且 不管 它,先 解決 通用模式下的問題。
if (devMode) { if (ActionReporter.isReportAfterInvocation(request)) { new Invocation(action, controller).invoke(); ActionReporter.report(target, controller, action); } else { ActionReporter.report(target, controller, action); new Invocation(action, controller).invoke(); } } else { new Invocation(action, controller).invoke(); }
我們先來 看看 這句話,這句話 其實 就是 把當前action和controller註入 到一個新的Invocation中,其中有 一個 invoke方法,因為 這牽扯 到過多的知識,連 我可能都 不太 懂 ,所以 暫且放到 一邊去,不做討論。
new Invocation(action, controller).invoke();
然後 我們 再看 下面一句 代碼,這說明可以從 controller裏面 得到render整個對象 。
Render render = controller.getRender();
然後 我們看 下面的 代碼 ,如果render是ForrwardActionRender。
if (render instanceof ForwardActionRender) { String actionUrl = ((ForwardActionRender)render).getActionUrl(); if (target.equals(actionUrl)) { throw new RuntimeException("The forward action url is the same as before."); } else { handle(actionUrl, request, response, isHandled); } return ; }
我們 首先 需要了解一下ForwardRender是一個 什麽 東西 ,然後 我們發現,其實 這 就是 一個 繼承 了Render類的一個子類,裏面就 多了一個actionUrl而已。
private String actionUrl; public ForwardActionRender(String actionUrl) { this.actionUrl = actionUrl.trim(); } public String getActionUrl() { return actionUrl; }
然後我們來看看 下面 的代碼,其實就是 自己啊,這裏實現了一個遞歸 ,自己調用 自己,為什麽呢,不得而知。
handle(actionUrl, request, response, isHandled);
那麽如果render為空,會執行如下 操作,設置一個 默認的Render,渲染器。
if (render == null) { render = renderManager.getRenderFactory().getDefaultRender(action.getViewPath() + action.getMethodName()); }
最後會有 這麽一句話 ,其實就是 設置request和response以及viewpath.
render.setContext(request, response, action.getViewPath()).render();
今天就 寫到這裏 ,重要的是查漏補缺。
JFinal源碼 分析之 Core包分析