Spring-AOP、Struts2拦截器、MyBatis Plugin实现原理比较(二)
Struts 2
?
Struts2是由StrutsPrepareAndExecuteFilter 的?doFilter 来处理每个HTTP请求的
?
由执行器的executeAction进入执行流程
execute.executeAction(request, response, mapping);?
实际的执行是由dispatcher发起的
public void executeAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException { dispatcher.serviceAction(request, response, servletContext, mapping); }
?
在serviceAction中会由ActionProxyFactory根据URL请求和struts的配置 , 生成对应Action的ActionProxy 实例?
?
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 { proxy.execute(); }?
?
Action的执行是由proxy.execute()触发的
在execute() ? 拦截器和Action执行都是由invocation调度的
?
public String execute() throws Exception { ActionContext nestedContext = ActionContext.getContext(); ActionContext.setContext(invocation.getInvocationContext()); String retCode = null; String profileKey = "execute: "; try { UtilTimerStack.push(profileKey); retCode = invocation.invoke(); } finally { if (cleanupContext) { ActionContext.setContext(nestedContext); } UtilTimerStack.pop(profileKey); } return retCode; }?
下面我们来看一下invocation的核心函数invoke
?
?
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 { resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); } finally { UtilTimerStack.pop(interceptorMsg); } } else { 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); } }
?
从InterceptorMapping 链中,也就是拦截器链中取出下一个InterceptorMapping?,拦截器被封装在里面
?
【对interceptors的初始化,也就是解析配置文件,加载所有的拦截器实例,在这里就不分析了】
?
final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
?
?
执行拦截器的拦截方法,参数是本身这个中央调度器
?
interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
?
?
再看一个拦截器的例子?LoggingInterceptor
?
?
? ? ? ? logMessage(invocation, START_MESSAGE); ? ?//记录开始
? ? ? ? String result = invocation.invoke();? ? ? //调度器 推进拦截器链
? ? ? ? logMessage(invocation, FINISH_MESSAGE); ? //记录结束
?
?
public class LoggingInterceptor extends AbstractInterceptor { private static final Logger LOG = LoggerFactory.getLogger(LoggingInterceptor.class); private static final String FINISH_MESSAGE = "Finishing execution stack for action "; private static final String START_MESSAGE = "Starting execution stack for action "; @Override public String intercept(ActionInvocation invocation) throws Exception { logMessage(invocation, START_MESSAGE); String result = invocation.invoke(); logMessage(invocation, FINISH_MESSAGE); return result; } ......}??
在invocation.invoke()推进拦截器链时,又会从InterceptorMapping 链中,也就是拦截器链中取出下一个InterceptorMapping?,下一个拦截器被封装在里面。接着执行拦截器的拦截方法,参数是本身这个中央调度器。下一个拦截器中也会调用?invocation.invoke();推进拦截器链前进。
?
如果拦截器已经执行完了, invoke() 会执行? resultCode = invokeActionOnly(); 执行对应的Action,并得到返回值。
?
前面的多次invoke()其实是形成了一个递归,当LoggingInterceptor中的 invocation.invoke();返回后,后面的记录结束语句会才会执行。这样这个LoggingInterceptor就形式了一个环绕的拦截器。
?
这个递归的调用,自然就是形成了层层包裹的结构,但在包裹的前后是否要执行相应的逻辑,就要看具体需求了。
?
?
从这里可以看出,对目标的拦截细节和责任链的推进要在拦截器中显式实现。
?
总结:
和MyBatis相比,虽然都是责任链的层层调用,链的推进和包裹的前后的执行逻辑,也要在实现中直接体现。
但这里的调度器封装了拦截器链,向下推进也都是在一个统一的逻辑中执行,并将这个中央调度器传递到每个拦截器中,以便拦截器控制推进逻辑。
而MyBatis是层层proxy,第次传给拦截器的调度器都是封闭了下一个目标,可能是一个proxy,也可能是target,责任链的推进,就是执行下一个对象的对应方法。拦截器没有被统一组织。
?
?
?