JFinal源碼 分析之 Core包分析

ActionHandler.java

  這個類繼承了上面 說的Handler類,首先咱們 上 幾個屬性 ,下面幾個 屬性咱們 須要 關心哪些東西 呢?首先 是ActionMapping和RenderManager,其中ActionMapping是經過 構造函數 注入進來的。而RenderManager.me其實 只是一個RenderManager的一個實例而已,java

複製代碼
    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進程啓動的。app

複製代碼
    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()方法中有一個方法 能夠初始化。ui

private void initActionMapping() {
        actionMapping = new ActionMapping(Config.getRoutes(), Config.getInterceptors());
        actionMapping.buildActionMapping();
        Config.getRoutes().clear();
    }

  從上面的代碼 當中,咱們 能夠 知道 幾個地方 ,ActionMapping確定是和route和intercertor(攔截器 )相關聯的,咱們 進入 ActionMapping的構造函數一探究竟,發現做者已經註釋掉 了 第二個 參數 。this

    ActionMapping(Routes routes, Interceptors interceptors) {
        this.routes = routes;
        // this.interceptors = interceptors;
    }

   咱們再來看看 handle方法:url

複製代碼
        if (target.indexOf('.') != -1) {
            return ;
        }
        
        isHandled[0] = true;
        String[] urlPara = {null};
        Action action = actionMapping.getAction(target, urlPara);
複製代碼

  首先若是 target包含.的 話 直接 結束,若是經過,把第一個isHandleed的布爾參數設置爲 true.下面 咱們 來 看看 getAction方法,spa

複製代碼
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.code

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錯誤 。blog

複製代碼
        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();

  今天就 寫到這裏 ,重要的是查漏補缺。

相關文章
相關標籤/搜索