通过一个简单的项目,使用debug模式,了解struts2action的处理过程。
首先看下struts2 的组织结构
通过上图,在Struts2中一个请求的生存周期包括:
1. 用户发送请求 : 用户为访问资源向服务器发送请求.
2. FilterDispatcher决定适当的action : FilterDispatcher接受请求然后决定调用适当的action
3. 调用拦截器 : 配置拦截器来应用常用的功能如工作流,验证,文件上传等,都是自动应用于请求的.
4. action的执行 : 然后action将被执行来调用诸如存储数据、检索数据之类的数据库相关操作.
5. 呈递输出 : 结果呈递到输出
6. 返回请求 : 请求通过拦截器按照相反的顺序返回,返回的请求可以允许我们执行一些清理或额外的处理
7. 向用户展示结果 : 控制权最终回归到输出结果至用户浏览器的Servlet容器
下面具体对源码进行了解:
一个http请求传过来,struts首先会调用FilterDispatcher类的doFilter()方法,通过它匹配一个request到action的映射关系,然后把action的处理委派给Dispatcher类的serviceAction()方法。
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
showDeprecatedWarning();
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
ServletContext servletContext = getServletContext();
String timerKey = "FilterDispatcher_doFilter: ";
<span style="white-space:pre"> </span>//找到映射关系
dispatcher.serviceAction(request, response, mapping);
}
}
在Dispatcher类的serviceAction()中会载入action类并调用相应的方法执行。具体步骤:
1. 创建action的长下文环境
2. 通过action的名字和命名空间创建ActionProxy代理
3. 执行action的方法
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping)
throws ServletException {
<span style="white-space:pre"> </span>
//创建上下文环境
Map<String, Object> extraContext = createContextMap(request, response, mapping);
// 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();
/创建action的代理
ActionProxy proxy = 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();
}
}
}
在创建代理的过程中,有一些准备工作,如通过配置文件会得到具体调用那个方法,初始化invocation的一些内容,包括:
1. 得到上下文环境Actioncontext
2. 通过反射机制,创建action类。
3. 通过配置文件获取拦截器。
public void init(ActionProxy proxy) {
this.proxy = proxy;
Map<String, Object> contextMap = createContextMap();
// Setting this so that other classes, like object factories, can use the ActionProxy and other
// contextual information to operate
ActionContext actionContext = ActionContext.getContext();
if (actionContext != null) {
actionContext.setActionInvocation(this);
}
//创建action
createAction(contextMap);
if (pushAction) {
stack.push(action);
contextMap.put("action", action);
}
invocationContext = new ActionContext(contextMap);
invocationContext.setName(proxy.getActionName());
、、
// get a new List so we don't get problems with the iterator if someone changes the list
List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
interceptors = interceptorList.iterator();
}
proxy.execute()的实现,主要是通过调用代理类invocation的invoke方法来完成的,这里就包括了一次调用各个拦截器,然后是action,result等。