以前做项目都是简单的jsp+bean,特没技术含量,终于有机会,自己有个机会决定选择框架,看了不少文章,最后决定用webwork+spring+hibernate来开发。看过了一些文章对这些有了大概的了解。计划五一前,把三个框架深入的研究一下。今天就从webwork开始把。曾经看过夏昕的webwork开发指南,大概流程明白了,具体细节还是不明白,所以下载下源码来看看。
我先大致说说我现在对webwork的理解吧。你们一看就知道了,我是初学者,如果有哪位朋友看到这篇文章,觉得里面有我理解不对的地方,希望给我告诉我一声哦。
webwork1我就不说了,我用的是webwork2,他是采用的webwork2+xwork1这样的框架,新框架与Servlet API 分离出来,这给我们的测试带来的极大地方便(这是不选struts的一个原因)。webwork负责把http请求分离出来,使得请求完全脱离Servlet,然后把请求封装到一个Map中,这样传入xwork中的不是Servlet请求,而是一个Map数据结构,xwork就负责根据这个Map数据填充好我们的VO对象,当然它使用的是拦截器的方式来实现的。然后被激活的Action就可以使用VO来进行相应的工作了。我们就顺着这个流程来逐步分析webwork+xwork的实现机制吧。那首先我们就想到的是webwork是如何把http请求封装成Map数据结构的呢?
在我们看了webwork的example,我们看到webwork所有服务都是以.action作为结尾的,但是http不没有以action结尾的服务资源,我们必须在web.xml里做如下的配置:
<servlet>
<servlet-name>webwork</servlet-name>
<servlet-class>com.opensymphony.webwork.dispatcher.ServletDispatcher</servlet-class>
<servlet>
<servlet-mapping>
<servlet-name>webwork</servlet-name>
<url-pattern>*.action</url-pattern>
<servlet-mapping>
通过这样的配置以后,应用程序Server就是知道凡是以action结尾的服务请求,都由ServletDipatcher接管。
因此,我就从ServletDispatcher源码开始分析。
首先,让我们看看ServletDispatcher.java文件开头的一段说明,这会给你一个对ServletDispatcher工作流程的大概了解。
在webwork中Dispatcher扮演着MVC中的控制器的角色。当请求发送到servlet之后,webwork会做哪些工作呢?
首先,action的名字会从servlet的路径中解析出来(i.e,/foo/bar/MyAction.action--->myAction)
然后,由request,response,parameters,session 和application属性组成的上下文将被创建。
接着,使用action的名字,路径以及上下文实例化ActionProxy,然后执行ActionProxy,最后Action的输出将返回给请求对象。
Servlet使用webwork属性初始化自己,下面这些属性将用于servlet的初始化:
webwork.configuration.xml.reload==true,则每一请求都会重新载入xml配置文件。这个一般用于开发阶段。
webwork.mutipart.saveDir:这个路径被用来保存临时的上传文件。缺省值是应用服务器的临时路径。
webwork.mutipart.maxSize:设置允许多路请求的最大值。
根据说明,大致是这样的。当请求发送到Servlet后,首先要调用ServletDispatcher的init来初始化Servlet,然后调用Service方法,
这个方法主要是得到Action对应的上下文,然后调用serviceAction来执行Action。在serviceAction方法中首先调用createContextMap来
创建Action的上下文环境。我们来仔细分析一下:看源码我们发现,实际上createContextMap就是把http请求的数据全部封装到一个HashMap里面去。
public static HashMap createContextMap(Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response, ServletConfig servletConfig) {
HashMap extraContext = new HashMap();
extraContext.put(ActionContext.PARAMETERS, parameterMap);
extraContext.put(ActionContext.SESSION, sessionMap);
extraContext.put(ActionContext.APPLICATION, applicationMap);
extraContext.put(ActionContext.LOCALE, (locale == null) ? request.getLocale() : locale);
extraContext.put(HTTP_REQUEST, request);
extraContext.put(HTTP_RESPONSE, response);
extraContext.put(SERVLET_CONFIG, servletConfig);
extraContext.put(ComponentInterceptor.COMPONENT_MANAGER, request.getAttribute(ComponentManager.COMPONENT_MANAGER_KEY));
// helpers to get access to request/session/application scope
extraContext.put("request", requestMap);
extraContext.put("session", sessionMap);
extraContext.put("application", applicationMap);
extraContext.put("parameters", parameterMap);
AttributeMap attrMap = new AttributeMap(extraContext);
extraContext.put("attr", attrMap);
return extraContext;
}
整个ServletDispatcher的核心就是serviceAction,然后来看看这个方法:
public void serviceAction(HttpServletRequest request, HttpServletResponse response, String namespace, String actionName, Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap) {
//创建了Action的上下文环境
HashMap extraContext = createContextMap(requestMap, parameterMap, sessionMap, applicationMap, request, response, getServletConfig());
extraContext.put(SERVLET_DISPATCHER, this);
// 如果存在值栈,就拷贝一个副本,传给新的action使用,否则就创建一个新的值栈。
OgnlValueStack stack = (OgnlValueStack) request.getAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY);
if (stack != null) {
extraContext.put(ActionContext.VALUE_STACK,new OgnlValueStack(stack));
}
实际这以下的工作都交给xwork来处理了。
try {
//实例化ActionProxy,然后执行Action.
ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);
request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY, proxy.getInvocation().getStack());
proxy.execute();
// If there was a previous value stack then set it back onto the request
if (stack != null){
request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY,stack);
}
} catch (ConfigurationException e) {
log.error("Could not find action", e);
sendError(request, response, HttpServletResponse.SC_NOT_FOUND, e);
} catch (Exception e) {
log.error("Could not execute action", e);
sendError(request, response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e);
}
}