这里我们只是讲一下最基本的原理,也就是当页面请求提交过来之后struts2是怎样处理的。
在网上找了一张图,地址是:
http://blog.csdn.net/wuwenxiang91322/article/details/11070513
其中控制器就是
StrutsPrepareAndExecuteFilter或FilterDispatcher
。在Struts2.1以前调用FilterDispatcher
,Struts2.1以后调用StrutsPrepareAndExecuteFilter
,控制器通过ActionMapper
得到action
的相关信息,通过ActionProxy
去读取相关配置文件,主要过程是在ActionInvocation(即DefaultActionInvocation)
和实际action
之间。我们就从控制器开始。
首先我们在org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
这个类的doFilter
方法开头设置一个断点,使用debug进行跟踪。在此方法中我们可以看到这样一段:
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);
}
说明:这里表示如果mapping为空表示没有找到相应的action,否则表示找到了相应的action,找到之后执行
execute.executeAction(request, response, mapping);
方法,我们跟进去,进去之后会发现执行的是方法:
dispatcher.serviceAction(request, response, mapping);
这个dispatcher
就是org.apache.struts2.dispatcher.Dispatcher
类,即执行Dispatcher
类的serviceAction
方法,继续跟进去。这个方法为:
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
throws ServletException {
Map<String, Object> extraContext = createContextMap(request, response, mapping);
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
......
try {
UtilTimerStack.push(timerKey);
String namespace = mapping.getNamespace();
String name = mapping.getName();
String method = mapping.getMethod();
ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, method, extraContext, true, false);
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
if (mapping.getResult() != null) {
Result result = mapping.getResult();
result.execute(proxy.getInvocation());
} else {
proxy.execute();
}
......
}
说明:
- 1.这个方法中我们首先看这两行
ValueStack stack = (ValueStack) request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack());
可以看到struts2将值栈存到了request域中,我们以后要想取得值栈中的内容可以使用上面的常量。
- 2.同时可以看到产生了一个
ActionProxy
对象,这个对象会通过ConfigurationManager
去读取配置文件的相关信息,之后就会执行其execute()
方法。跟踪此方法会发现此方法最后
return invocation.invoke();
也就是执行com.opensymphony.xwork2.DefaultActionInvocation
对象的invoke方法,而此类中我们可以看到包含了我们自己的action和一系列的拦截器(interceptor)。跟踪此方法:
if (interceptors.hasNext()) {
final InterceptorMapping interceptor = interceptors.next();
String interceptorMsg = "interceptor: " + interceptor.getName();
UtilTimerStack.push(interceptorMsg);
try {
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
}
finally {
UtilTimerStack.pop(interceptorMsg);
}
} else {
resultCode = invokeActionOnly();
}
说明:代码中这样一段可以看到首先执行各类拦截器,当拦截器执行完之后执行invokeAction()
这个方法。
首先我们看
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
这里调用的是拦截器的intercept
方法,在此方法中我们可以看到
result = invocation.invoke();
也就是说继续调用DefaultActionInvocation
的invoke
方法,这样就会调用下一个拦截器,当将所有拦截器都调用一遍之后,才会执行DefaultActionInvocation
的invokeActionOnly();
方法,我们跟进去会发现执行的是
return invokeAction(getAction(), proxy.getConfig());
在invokeAction
方法中:
String methodName = proxy.getMethod();
此时拿到的方法就是我们的action中的execute方法,然后就执行此方法,之后就返回去,经过一些列的拦截器之后返回到
com.opensymphony.xwork2.DefaultActionInvocation
然后返回到org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
类,最后在页面中响应。
最后:根据原理图和debug调试基本上可以对struts的原理有个比较大概的了解了。