JFinal源码走读_2_运行时初探

来源:互联网 发布:什么软件跑分准 编辑:程序博客网 时间:2024/04/26 10:26

      • 运行时入口
        • handlerhandletarget request response isHandled的探究
          • new ActionInvocationaction controllerinvoke的探究
          • rendersetContextrequest response actiongetViewPathrender的探究
      • 运行时小结

运行时入口

由于filter拦截了所有的请求url,所以所有访问jfinal webapp 的请求都会被JfinalFilter的doFilter处理。故运行时入口为JFinalFilter的doFilter方法。

public void doFilter(ServletRequest req, ServletResponse res,            FilterChain chain) throws IOException, ServletException {        // 获取request,response和为request设置编码        HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) res;        request.setCharacterEncoding(encoding);        // 获取requestUrl,url:port/webappname/xx,/webappname/xx即requestUrl        String target = request.getRequestURI();        // contextPath为/webappname,而action中的actionkey是不包含contextpath,所以此处需将requestUrl中的contextPath这一段截掉        // 此时对于初始化时contextPathLength的作用就明了了,截取之后的只为/xx        if (contextPathLength != 0)            target = target.substring(contextPathLength);        // 声明hander处理的标识量        boolean[] isHandled = { false };        try {            // 很明显,此句才是这段代码中的重点戏,延后分析,实际的请求处理调用。            handler.handle(target, request, response, isHandled);        } catch (Exception e) {            // 异常日志记录            if (log.isErrorEnabled()) {                String qs = request.getQueryString();                log.error(qs == null ? target : target + "?" + qs, e);            }        }        // 此句涉及到handle链的结构和handler的具体处理,初始化阶段时,handler链的末端是actionHandler,而只有调用acitonHandler的handle方法之后,isHandled[0]才会被赋值为true        // handler.handle方法内部会递归调用下一个handler的handle方法,而有些处理可能调用不到最末端的actionHandle的handle方法,此时isHandled[0]为false        // 虽然demo中没有配置额外的handler,但是如ServerNameRedirect301Handler,UrlSkipHandler都是在满足一定条件才会继续递归往下调用的        if (isHandled[0] == false)            // jfinal程序中可以配置多个filter,由此句可见端倪            chain.doFilter(request, response);    }

handler.handle(target, request, response, isHandled)的探究

由于暂时没有其他的handle配置,所以暂时只分析ActionHandler的handle方法实现

public final void handle(String target, HttpServletRequest request,            HttpServletResponse response, boolean[] isHandled) {        // target含有‘.’ 则不进行处理        if (target.indexOf('.') != -1) {            return;        }        // 使标识量为true,说明handler链上的所有handler都已经处理过了        isHandled[0] = true;        String[] urlPara = { null };        // 获取target对应的action,即actionKey对应的action        Action action = actionMapping.getAction(target, urlPara);        // 没有获取到对应的action,记录异常,并渲染404页面,处理完成,响应返回客户端        if (action == null) {            if (log.isWarnEnabled()) {                String qs = request.getQueryString();                log.warn("404 Action Not Found: "                        + (qs == null ? target : target + "?" + qs));            }            renderFactory.getErrorRender(404).setContext(request, response)                    .render();            return;        }        try {            // 为每个请求都新建一个controller实例,感觉此处应有改善空间,对于低并发来说,没什么压力,高并发的话,开销不应该考虑么?            // 以空间换效率应该是可行的,由actionHandle维护一个Controller缓存池            Controller controller = action.getControllerClass().newInstance();            // 初始化 简单赋值            controller.init(request, response, urlPara[0]);            // 根据devMode决定是否在控制台打印处理信息            if (devMode) {                boolean isMultipartRequest = ActionReporter                        .reportCommonRequest(controller, action);                new ActionInvocation(action, controller).invoke();                if (isMultipartRequest)                    ActionReporter.reportMultipartRequest(controller, action);            } else {                // 1.核心代码,延后分析                new ActionInvocation(action, controller).invoke();            }            // 获取render,render的具体值是由上一步得到的,因为每个action最终都需要渲染,最后一步执行的方法确定了render的值,对于某些不涉及到渲染操作的action,比如对数据库进行存储的,会返回null。            Render render = controller.getRender();            // 暂时没碰到ActionRender,碰到了再回头分析            if (render instanceof ActionRender) {                String actionUrl = ((ActionRender) 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;            }            // 对于某些不涉及到渲染操作的action,比如对数据库进行存储的,会返回null,此时将render赋值为jfinal的缺省设置            if (render == null)                render = renderFactory.getDefaultRender(action.getViewPath()                        + action.getMethodName());            // 为render设置上下文环境并渲染            // 至此actionhandler的整个处理流程走完            // jspRender的render方法延后分析            render.setContext(request, response, action.getViewPath()).render();        }        // 处理异常,记录日志,渲染错误页        catch (RenderException e) {            if (log.isErrorEnabled()) {                String qs = request.getQueryString();                log.error(qs == null ? target : target + "?" + qs, e);            }        } catch (ActionException e) {            int errorCode = e.getErrorCode();            if (errorCode == 404 && log.isWarnEnabled()) {                String qs = request.getQueryString();                log.warn("404 Not Found: "                        + (qs == null ? target : target + "?" + qs));            } else if (errorCode == 401 && log.isWarnEnabled()) {                String qs = request.getQueryString();                log.warn("401 Unauthorized: "                        + (qs == null ? target : target + "?" + qs));            } else if (errorCode == 403 && log.isWarnEnabled()) {                String qs = request.getQueryString();                log.warn("403 Forbidden: "                        + (qs == null ? target : target + "?" + qs));            } else if (log.isErrorEnabled()) {                String qs = request.getQueryString();                log.error(qs == null ? target : target + "?" + qs, e);            }            e.getErrorRender().setContext(request, response).render();        } catch (Throwable t) {            if (log.isErrorEnabled()) {                String qs = request.getQueryString();                log.error(qs == null ? target : target + "?" + qs, t);            }            renderFactory.getErrorRender(500).setContext(request, response)                    .render();        }    }

new ActionInvocation(action, controller).invoke();的探究

1.新对象

ActionInvocation(Action action, Controller controller) {        this.controller = controller;        this.inters = action.getInterceptors();        this.action = action;    }

2.invoke()方法

public void invoke() {        // inters为此action的拦截器栈,依次执行此action的拦截器,由初始化过程可知,拦截器顺序依次为 全局,controller,method         // 此方法是个递归方法 拦截器01_before->拦截器02_before->xx_before->action.getMethod.invoke(controller,NULL_ARGS)->xx_after->拦截器02_after->拦截器01_after        if (index < inters.length)            inters[index++].intercept(this);        else if (index++ == inters.length)    // index++ ensure invoke action only one time            // 拦截器执行完,则反射执行action对应的method方法            try {                action.getMethod().invoke(controller, NULL_ARGS);            }            // 异常处理            catch (InvocationTargetException e) {                Throwable cause = e.getTargetException();                if (cause instanceof RuntimeException)                    throw (RuntimeException)cause;                throw new RuntimeException(e);            }            catch (RuntimeException e) {                throw e;            }            catch (Exception e) {                throw new RuntimeException(e);            }    }

render.setContext(request, response, action.getViewPath()).render()的探究

只分析jspRender的render方法

public void render() {        // 在 jsp 页面使用如下指令则无需再指字符集, 否则是重复指定了,与页面指定的不一致时还会出乱码        // <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>        // response.setContentType(contentType);        // response.setCharacterEncoding(encoding);        try {            // 暂时不清楚activeRecord是何许神圣,暂不分析            if (isSupportActiveRecord)                supportActiveRecord(request);            // jspRender利用基础的分发器转发请求,至此一个请求到相应的流程走完,即V->C->V            request.getRequestDispatcher(view).forward(request, response);        } catch (Exception e) {            throw new RenderException(e);        }    }

运行时小结

运行时从filter接管->处理器链处理->actionHandle处理->具体action处理->render 结束,此中包含了actionRender,由于暂时没有碰到actionRender,暂不分析

0 0