1.org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter()方法中
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); //设置编码和本地化信息 prepare.createActionContext(request, response); //创建ActionContext对象 prepare.assignDispatcherToThread(); //分配当前线程的分发器 if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { chain.doFilter(request, response); } else { request = prepare.wrapRequest(request); //对request对象进行封装 //获取ActionMapping对象, ActionMapping对象对应一个action详细配置信息 ActionMapping mapping = prepare.findActionMapping(request, response, true); if (mapping == null) { boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else { execute.executeAction(request, response, mapping); //执行Action请求, 进入下面方法 重要 } } } finally { prepare.cleanupRequest(request); } }
- 设置编码和本地化信息
- 创建ActionContext对象
- 分配当前线程的分发器
- 将request对象进行封装
- 获取ActionMapping对象, ActionMapping对象对应一个action详细配置信息啊阿斯顿
- 执行Action请求, 进入下面方法
2.org.apache.struts2.dispatcher.Dispatcher.serviceAction()方法:
1 public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context, ActionMapping mapping) throws ServletException { 2 3 Map<String, Object> extraContext = createContextMap(request, response, mapping, context); 4 5 //首先获取当前请求是否已经有valueStack对象, 这样做的目的是在接受到chain跳转方式的请求时, 可以直接接管上次请求的action 6 ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); 7 boolean nullStack = stack == null; 8 if (nullStack) { 9 ActionContext ctx = ActionContext.getContext(); //如果请求中没有ValueStack对象, 获取当前线程的ActionContext对象 10 if (ctx != null) { 11 stack = ctx.getValueStack(); //从ActionContext中获取ValueStack 12 } 13 } 14 if (stack != null) { 15 extraContext.put(ActionContext.VALUE_STACK, valueStackFactory.createValueStack(stack)); //将事先处理好的请求中的参数put到ValueStack中 16 } 17 18 String timerKey = "Handling request from Dispatcher"; 19 try { 20 UtilTimerStack.push(timerKey); 21 String namespace = mapping.getNamespace(); 22 String name = mapping.getName(); 23 String method = mapping.getMethod(); //获取ActionMapping中配置的namespace, name, method值 24 25 Configuration config = configurationManager.getConfiguration(); //根据配置获取当前Action的代理对象ActionProxy(这个过程中会创建Action对象, 同时返回的代理对象是StrutsActionProxy的实例) 26 ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy( 27 namespace, name, method, extraContext, true, false); 28 29 request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); //向request中设置ValueStack对象 30 31 // if the ActionMapping says to go straight to a result, do it! 32 if (mapping.getResult() != null) { 33 Result result = mapping.getResult(); 34 result.execute(proxy.getInvocation()); 35 } else { 36 proxy.execute(); //进入ActionProxy的处理 重要 37 }
- 首先获取当前请求是否已经有valueStack对象, 这样做的目的是在接受到chain跳转方式的请求时, 可以直接接管上次请求的action
- 如果请求中没有ValueStack对象, 获取当前线程的ActionContext对象
- 从ActionContext中获取ValueStack
- 将事先处理好的请求中的参数put到ValueStack中
- 获取ActionMapping中配置的namespace, name, method值
- 根据配置获取当前Action的代理对象ActionProxy(这个过程中会创建Action对象, 同时返回的代理对象是StrutsActionProxy的实例)
- 向request中设置ValueStack对象
- 进入ActionProxy的处理
3.org.apache.struts2.impl.StrutsActionProxy.execute()方法:
1 public String execute() throws Exception { 2 ActionContext previous = ActionContext.getContext(); //准备上下文环境 //StrutsActionProxy是继承自com.opensymphony.xwork2.DefaultActionProxy的, 在这个代理对象内部实际上就持有了 //com.opensymphony.xwork2.DefaultActionInvocation的一个实例的 3 ActionContext.setContext(invocation.getInvocationContext()); 4 try { 5 return invocation.invoke(); //此时, 调用它的invoke方法 6 } finally { 7 if (cleanupContext) 8 ActionContext.setContext(previous); 9 } 10 }
- 准备上下文环境
- StrutsActionProxy是继承自com.opensymphony.xwork2.DefaultActionProxy的, 在这个代理对象内部实际上就持有了DefaultActionInvocation的一个实例.
- DefaultActionInvocation对象中保存了Action调用过程中需要的一切信息
- 此时, 调用它的invoke方法
4.com.opensymphony.xwork2.DefaultActionInvocation.invoke()方法:
1 public String invoke() throws Exception { 2 String profileKey = "invoke: "; 3 try { 4 UtilTimerStack.push(profileKey); 5 6 if (executed) { 7 throw new IllegalStateException("Action has already executed"); 8 } 9 10 if (interceptors.hasNext()) { 11 final InterceptorMapping interceptor = interceptors.next(); 12 String interceptorMsg = "interceptor: " + interceptor.getName(); 13 UtilTimerStack.push(interceptorMsg); 14 try { //首先会顺序的递归执行当前Action中所配置的所有的拦截器, 直到拦截器遍历完毕调用真正的Action 15 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); 16 } 17 finally { 18 UtilTimerStack.pop(interceptorMsg); 19 } 20 } else { //通过调用DefaultActionInvocation的invokeActionOnly()方法去反射调用Action, 调用过程中, 会从当前的invocation对象中得到Action的实例, // 并通过代理对象获得配置信息. 21 resultCode = invokeActionOnly(); 22 }
- 首先会顺序的递归执行当前Action中所配置的所有的拦截器, 直到拦截器遍历完毕调用真正的Action
- 通过调用DefaultActionInvocation的invokeActionOnly()方法去反射调用Action, 过程中, 会从当前的invocation对象中得到Action的实例, 并通过代理对象获得配置信息.
5.com.opensymphony.xwork2.DefaultActionInvocation.invokeAction()方法:
- 反射获得当前请求分发的Action中的方法对象
- 以传入的Action实例反射调用该处理方法
- 如果返回的结果不是com.opensymphony.xwork2.Result的实例, 返回强转为字符串的结果.
6.回到1.4所在方法继续:
- 将invokeAction返回的resultCode存储到当前的invokeAction实例中
- 进入result处理
7.com.opensymphony.xwork2.DefaultActionInvocation.executeResult()方法:
- 创建result对象(com.opensymphony.xwork2.DefaultActionInvocation.createResult()方法)
- 如果当时调用Action返回了Result对象, 则直接返回
- 否则, 通过proxy对象获取配置信息, 根据resultCode获取到Result对象
- 使用ognl翻译result中的用${}和%{}标识引用ValueStack中的值的参数.
- 调用执行result
8.org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute()方法
- 准备执行环境: request, pageContext等等
- 判断有没有合适的分发器, 如果没有, 发404消息
- 在request对象中设定两个属性:
- struts.view_uri: 分发之后的url地址
- struts.request_uri: 真正请求的url地址
- 发送真正的响应信息
9.至此, Action的处理完毕, 回归到1.4.1中指明的递归调用那里, 逐步的返回并执行每个拦截器的invokeAction.invoke()后面的代码, 从这里也就可以看出拦截器的机制.
c