JFinal源码走读_2_运行时初探
来源:互联网 发布:什么软件跑分准 编辑:程序博客网 时间:2024/04/26 10:26
- 运行时入口
- handlerhandletarget request response isHandled的探究
- new ActionInvocationaction controllerinvoke的探究
- rendersetContextrequest response actiongetViewPathrender的探究
- handlerhandletarget request response isHandled的探究
- 运行时小结
- 运行时入口
运行时入口
由于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
- JFinal源码走读_2_运行时初探
- JFinal源码走读_1_jfinal初始化
- JFinal源码走读_3_ActiveRecord初始化
- JFinal源码走读_5_Validator校验源码分析
- JFinal源码走读_4_ActiveRecord CURD分析
- Spark运行流程源码走读
- Docker 源码走读 - 在运行 Docker run 时发生了什么?
- Apache Spark源码走读之 Job的提交与运行
- Twemproxy源码走读(4):运行主流程
- MiniGUI源码走读
- MiniGUI源码走读
- hadoop源码走读
- MiniGUI源码走读
- MiniGUI源码走读
- JFianl源码走读_7_Interceptor
- DAGScheduler 源码走读
- Kubelet 源码走读(1)
- Spark源码走读概述
- android中用代码触发一个按钮的点击事件
- js获取一个对象其所有属性和属性对应的值
- 试试
- Set Matrix Zeroes
- 信管14:前两章学习任务及 学习问题收集器
- JFinal源码走读_2_运行时初探
- 打一辈子的工才是最大的风险
- 例题2.28 桥上的绳索 UVa1356
- View Touch 事件分发
- RSS Feeds List
- Android 如何实现 焦点图的 无线循环滑动的状态?
- 计算一个无符号整数的二进制中0和1的个数
- 使用Canvas和Paint自己绘制一个折线图
- 为什么不用table布局