WebX学习二——URL请求流程分析
2015-06-15 20:26
197 查看
URL请求流程分析
1.在index页面中设置了得到如下链接
当这个get请求发出的时候,流程是这样的:
首先,它被webx中配置的Filter捕获:
进入源码分析发现:该请求进入了WebxFrameworkFilter的doFilter方法:
@Override protected void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { String path = getResourcePath(request); if (isExcluded(path)) { log.debug("Excluded request: {}", path); chain.doFilter(request, response); return; } else { log.debug("Accepted and started to process request: {}", path); } try { getWebxComponents().getWebxRootController().service(request, response, chain); } catch (IOException e) { throw e; } catch (ServletException e) { throw e; } catch (Exception e) { throw new ServletException(e); } }
使用getResourcePath(request)得到path,然后通过isExcluded方法进行判断是否不进行处理。
不进行处理的urlPattern在配置中进行了配置。
显然最后返回false,不排除在外,因此webx接管了这个请求url。
之后getWebxComponents.getWebxRootController.service;
getWebxComponents得到配置中配置的所有components。然后获得处理web请求的WebxRootController,执行它的service方法,入参为原始的HttpServletRequest和HttpServletResponse,以及配置中配置的FilterChain.
void service(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws Exception;
然后进入service方法进行请求的分类:
public final void service(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws Exception { RequestContext requestContext = null; try { requestContext = assertNotNull(getRequestContext(request, response), "could not get requestContext"); // 如果请求已经结束,则不执行进一步的处理。例如,当requestContext已经被重定向了,则立即结束请求的处理。 if (isRequestFinished(requestContext)) { return; } // 请求未结束,则继续处理... request = requestContext.getRequest(); response = requestContext.getResponse(); // 如果是一个内部请求,则执行内部请求 if (handleInternalRequest(request, response)) { return; } // 如果不是内部的请求,并且没有被passthru,则执行handleRequest if (isRequestPassedThru(request) || !handleRequest(requestContext)) { // 如果请求被passthru,或者handleRequest返回false(即pipeline放弃请求), // 则调用filter chain,将控制交还给servlet engine。 giveUpControl(requestContext, chain); } } catch (Throwable e) { handleException(requestContext, request, response, e); } finally { commitRequest(requestContext); } }
其中有
handleInternalRequest和 处理非内部请求的代码块。
接下来判断是否是内部请求,该方法在是内部请求之后会执行然后返回true:
private boolean handleInternalRequest(HttpServletRequest request, HttpServletResponse response) throws Exception { RequestHandlerContext internalRequestHandlerContext = internalHandlerMapping.getRequestHandlerContext(request, response); if (internalRequestHandlerContext == null) { return false; } // 如果是一个内部请求,则执行内部请求 internalRequestHandlerContext.handleRequest(); return true; }
显然本例中返回了false,意味着它不是内部请求,它是一个外部的通过页面传来的链接。
在判断了既不是paththru的请求也不是内部请求,进入if中的handleRequest(requestContext)
寻找path对应的components。
public WebxComponent findMatchedComponent(String path) { if (!path.startsWith("/")) { path = "/" + path; } WebxComponent defaultComponent = getDefaultComponent(); WebxComponent matched = null; // 前缀匹配componentPath。 for (WebxComponent component : this) { if (component == defaultComponent) { continue; } String componentPath = component.getComponentPath(); if (!path.startsWith(componentPath)) { continue; } // path刚好等于componentPath,或者path以componentPath/为前缀 if (path.length() == componentPath.length() || path.charAt(componentPath.length()) == '/') { matched = component; break; } } // fallback to default component if (matched == null) { matched = defaultComponent; } return matched; }
在寻找对应的component的时候,如果没有找到,则说明在配置里面没有配对应的component,则选择defaultComponent进行配置。
然后将该component放入request作为参数,再进入service的handle.invoke():
执行invokeNext()
public void invokeNext() { assertInitialized(); if (broken) { return; } try { executingIndex++; if (executingIndex <= executedIndex) { throw new IllegalStateException(descCurrentValve() + " has already been invoked: " + valves[executingIndex]); } executedIndex++; if (executingIndex < valves.length) { Valve valve = valves[executingIndex]; try { if (log.isTraceEnabled()) { log.trace("Entering {}: {}", descCurrentValve(), valve); } valve.invoke(this); } catch (PipelineException e) { throw e; } catch (Exception e) { throw new PipelineException("Failed to invoke " + descCurrentValve() + ": " + valve, e); } finally { if (log.isTraceEnabled()) { log.trace("...Exited {}: {}", descCurrentValve(), valve); } } if (executedIndex < valves.length && executedIndex == executingIndex) { if (log.isTraceEnabled()) { log.trace("{} execution was interrupted by {}: {}", new Object[] { descCurrentPipeline(), descCurrentValve(), valve }); } } } else { if (log.isTraceEnabled()) { log.trace("{} reaches its end.", descCurrentPipeline()); } } } finally { executingIndex--; } }
其中的一个重点是方法:valve.invoke(this);
这是一个递归执行过程,将this对象传入下一个valve进行处理,然后再层层深入,直到完成配置中 配置的valve流程再一层层返回。
而我们所定义的业务层的方法,也就在每一个valve中,不同种类的valve代理着不同的业务方法,这也就是为什么有的业务方法使用execute命名,有的使用doXXX作为方法名:
最终boolean返回served=true;完成请求并commitRequest。
相关文章推荐
- 【Scala】头等函数与函数即对象
- poj2509---抽k根烟就换一支,求能抽烟的总数
- 《编程珠玑》阅读小记(9) — 取样问题
- Android布局优化之Merge Include ViewStub使用与源码分析
- 文本编辑器vi和vim(2)
- mac 下查找文件以及文件夹
- 【Scala】单例对象与伴生对象
- 大数据时代的技术hive:hive的数据类型和数据模型
- STL用法
- Android的ADB工具使用
- 字母重排-程序设计编程
- QCombobox组合框 样式表 举例
- 开关电源调试记录二
- 推荐一款超强大的基于Angularjs的自动完成(Autocomplete)标签及标签组插件–ngTagsInput
- JDK动态代理、责任链在mybatis中的应用
- Android模拟器adb命令介绍
- j2se学习笔记-继承&构造方法
- Android app项目开发步骤总结
- 谁欠谁的幸福
- sgu-263 Towers