`
qilixiang012
  • 浏览: 202584 次
文章分类
社区版块
存档分类
最新评论

struts2 拦截器原理

 
阅读更多
拦截器是struts2处理的核心,本文主要说struts2的拦截器的基本原理/实现,其它框架处理的东西就不说了,得自己再看了。
struts2版本:2.2.3
<wbr style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px"><p><span style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px">当一个请求来了后,从org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter 开始处理</span></p> <p><span style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px"></span></p> <pre code_snippet_id="362367" snippet_file_name="blog_20140525_1_5346810" name="code" class="java"> public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; try { //设置编码 prepare.setEncodingAndLocale(request, response); //创建actionContext prepare.createActionContext(request, response); prepare.assignDispatcherToThread(); //如果不是struts的请求则继续由其它过滤器执行 if ( excludedPatterns != null &amp;&amp; prepare.isUrlExcluded(request, excludedPatterns)) { chain.doFilter(request, response); } else { //包装request,对有文件上传的特殊处理下 request = prepare.wrapRequest(request); //查找对应的ActionMapping ActionMapping mapping = prepare.findActionMapping(request, response, true); //如果找不到ActionMapping则当作静态资源来处理 if (mapping == null) { boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else { //使用ActionMapping来执行action execute.executeAction(request, response, mapping); } } } finally { prepare.cleanupRequest(request); } } </pre> <br><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px">跟踪execute.executeAction(),则到了 org.apache.struts2.dispatcher.Dispatcher,如下:</span><br style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px"><pre code_snippet_id="362367" snippet_file_name="blog_20140525_2_2903812" name="code" class="java"> public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { Map&lt;String, Object&gt; extraContext = createContextMap(request, response, mapping, context); // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); boolean nullStack = stack == null; if (nullStack) { ActionContext ctx = ActionContext.getContext(); if (ctx != null) { stack = ctx.getValueStack(); } } if (stack != null) { extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack)); } String timerKey = "Handling request from Dispatcher"; try { UtilTimerStack.push(timerKey); String namespace = mapping.getNamespace(); String name = mapping.getName(); String method = mapping.getMethod(); Configuration config = configurationManager.getConfiguration(); //使用StrutsActionProxyFactory(ActionProxyFactory的一个实现)创建action代理对象 //proxy实际上是org.apache.struts2.impl.StrutsActionProxy类型 ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( namespace, name, method, extraContext, true, false); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); // if the ActionMapping says to go straight to a result, do it! if (mapping.getResult() != null) { Result result = mapping.getResult(); result.execute(proxy.getInvocation()); } else { //执行action proxy.execute(); } // If there was a previous value stack then set it back onto the request if (!nullStack) { request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); } } catch (ConfigurationException e) { // WW-2874 Only log error if in devMode if(devMode) { String reqStr = request.getRequestURI(); if (request.getQueryString() != null) { reqStr = reqStr + "?" + request.getQueryString(); } LOG.error("Could not find action or result\n" + reqStr, e); } else { LOG.warn("Could not find action or result", e); } sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e); } catch (Exception e) { sendError(request, response, context, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e); } finally { UtilTimerStack.pop(timerKey); } } </pre> <br><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px">DefaultActionProxyFactory创建ActionProxy,在com.opensymphony.xwork2.DefaultActionProxyFactory:</span><br><p><span style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"></span></span></p> <pre code_snippet_id="362367" snippet_file_name="blog_20140525_3_2762108" name="code" class="java"> public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map&lt;String, Object&gt; extraContext, boolean executeResult, boolean cleanupContext) { ActionInvocation inv = new DefaultActionInvocation(extraContext, true); container.inject(inv); return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext); } </pre> <br><span style="color:#000000; line-height:28px; font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px">接下来看看</span><span style="color:#008000; line-height:28px; font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px"><span style="color:#000000">org.apache.struts2.impl.StrutsActionProxy的execute()方法,如下:</span><strong><br></strong></span><pre code_snippet_id="362367" snippet_file_name="blog_20140525_4_3492456" name="code" class="java"> public String execute() throws Exception { ActionContext previous = ActionContext.getContext(); ActionContext.setContext(invocation.getInvocationContext()); try { //这里就是调用拦截器的入口了 return invocation.invoke(); } finally { if (cleanupContext) ActionContext.setContext(previous); } }</pre> <br><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px">最关键的,com.opensymphony.xwork2.DefaultActionInvocation.invoke()方法,这个DefaultActionInvocation是ActionInvocation的一个实现类,如下:</span><br><p><span style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"></span></span></span></p> <pre code_snippet_id="362367" snippet_file_name="blog_20140525_5_3350752" name="code" class="java"> //保存了执行当前action方法时需要调用的拦截器栈,按照struts.xml中配制的拦截器顺序,从前到后,依次加入到了这个Iterator里面 protected Iterator&lt;InterceptorMapping&gt; interceptors; public String invoke() throws Exception { String profileKey = "invoke: "; try { UtilTimerStack.push(profileKey); if (executed) { throw new IllegalStateException("Action has already executed"); } //如果当前还有下一个,则继续执行拦截器 if (interceptors.hasNext()) { final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next(); String interceptorMsg = "interceptor: " + interceptor.getName(); UtilTimerStack.push(interceptorMsg); try { //执行拦截器的intercept()方法,并将当前ActionInvocation对象传递给这个方法 //这样,当一个拦截器执行完自己的处理后,需要让框架继续执行下一个拦截器的时候,直接使用actionInvocation.invoke()方法,当前这个方法又会被调一次,这其实就是一个递归了,递归方法是ActionInvocation.invoke(),结束条件是interceptors.hasNext() resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } finally { UtilTimerStack.pop(interceptorMsg); } } else { //拦截器全部都执行了,那么最后来执行action,跳出递归了 resultCode = invokeActionOnly(); } // this is needed because the result will be executed, then control will return to the Interceptor, which will // return above and flow through again if (!executed) { if (preResultListeners != null) { for (Object preResultListener : preResultListeners) { PreResultListener listener = (PreResultListener) preResultListener; String _profileKey = "preResultListener: "; try { UtilTimerStack.push(_profileKey); listener.beforeResult(this, resultCode); } finally { UtilTimerStack.pop(_profileKey); } } } // now execute the result, if we're supposed to if (proxy.getExecuteResult()) { executeResult(); } executed = true; } return resultCode; } finally { UtilTimerStack.pop(profileKey); } }</pre> <br><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px">基本原理到此为止,下面弄个小例子再说明一下:</span><br><p><span style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"></span></span></span></span></p> <pre code_snippet_id="362367" snippet_file_name="blog_20140525_6_3209048" name="code" class="java">//拦截器,相当于struts2的拦截器 public interface Interceptor { String intercept(InvocationContext context); } </pre> <br><pre code_snippet_id="362367" snippet_file_name="blog_20140525_7_6447651" name="code" class="java">//很多拦截器的实现 public class ExceptionInterceptor implements Interceptor { public String intercept(InvocationContext context) { // 对异常的处理 System.out.println("\t\t\tExceptionInterceptor 处理异常"); return context.invoke(); } } public class FileUploadInterceptor implements Interceptor { public String intercept(InvocationContext context) { // 处理文件上传相关 System.out.println("\t\t\tFileUploadInterceptor 处理文件上传"); return context.invoke(); } } public class ParameterInterceptor implements Interceptor { public String intercept(InvocationContext context) { // 处理请求的参数 System.out.println("\t\t\tParameterInterceptor 处理请求参数"); return context.invoke(); } }</pre> <br><pre code_snippet_id="362367" snippet_file_name="blog_20140525_8_2194510" name="code" class="java">//执行拦截器的invocation上下文,相当于struts2的ActionInvocation public class InvocationContext { // 这里存放当前执行当前action所需要执行的拦截器栈 private Iterator&lt;Interceptor&gt; interceptorIterator = null; private String prefix = ""; public InvocationContext() { // 模拟从配制文件中相应的规则取拦截器栈 ArrayList&lt;Interceptor&gt; list = new ArrayList&lt;Interceptor&gt;(); list.add(new ExceptionInterceptor()); list.add(new FileUploadInterceptor()); list.add(new ParameterInterceptor()); interceptorIterator = list.iterator(); } public String invoke() { // 是否还有拦截器需要执行 if (interceptorIterator.hasNext()) { // 获取下一个需要执行的拦截器 Interceptor interceptor = interceptorIterator.next(); String name = interceptor.getClass().getName(); name = prefix + name; System.out.println(name + " intercept start..."); prefix += "\t"; // Interceptor的所有intercept方法实现里面,最后都调用了InvocationContext.invoke()方法 // 其实就是一个递归,只不过invoke()的下一个递归是在Interceptor.intercept()里面调用的 // 所以说为什么Interceptor.intercept()方法要加个InvocationContext的参数呢,作用就在于此 String result = interceptor.intercept(this); System.out.println(name + " intercept end..."); return result; } else {// 所有的拦截器都执行完了,那就来执行action对应的方法 return executeAction(); } } private String executeAction() { System.out.println(prefix + "executeAction success."); return "success"; } } </pre> <br><pre code_snippet_id="362367" snippet_file_name="blog_20140525_9_8988143" name="code" class="java">//模拟请求进行测试 public class Test { public static void main(String[] args) { InvocationContext context = new InvocationContext(); System.out.println("请求开始了..."); context.invoke(); System.out.println("请求处理完了..."); } }</pre> <br><img src="http://img.blog.csdn.net/20140525143654234" alt=""><br><p><span style="line-height:28px; color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:16px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"><br></span></span></span></span></p> <p><span style="font-family:Hiragino Sans GB W3,Hiragino Sans GB,Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; color:#3d3d3d"><span style="line-height:28px">参考链接:</span></span></p> <p><span style="font-family:Hiragino Sans GB W3,Hiragino Sans GB,Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; color:#3d3d3d"><span style="line-height:28px"><a target="_blank" href="http://sunjun041640.blog.163.com/blog/static/25626832201171510525222/">http://sunjun041640.blog.163.com/blog/static/25626832201171510525222/</a><br></span></span></p> <div><span style="color:rgb(61,61,61); font-family:'Hiragino Sans GB W3','Hiragino Sans GB',Arial,Helvetica,simsun,u5b8bu4f53; font-size:14px; line-height:28px"><br></span></div> </wbr>
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics