WebWork执行流程

com.opensymphony.webwork下有两个类:public class ServletActionContext extends ActionContext implements WebWorkStatics;
这个类是静态工具类,其内的方法均依赖com.opensymphony.xwork.ActionContext类,而这个类提供了Action类的执行上下文.我们跟踪这个上下文的生命周期:

客户请求发送到Webserver,它将请求转发到Servlet容器,容器匹配一个Sertlet,然后调用其sevice()方法.在WebWork中这个servlet是ServletDispatcher,其中的serviceAction方法通过代理模式从WebWork进入到XWork对象世界,在那里对客户请求数据对象执行处理,通过执行根据配置上下文和执行上下文设置的Action和result把响应数据发回客户端,发回的动作可能发生在Result中,也可能发生在Interceptor中.开始代码之旅.

下面是serviceAction代码:


public void serviceAction(HttpServletRequest request, HttpServletResponse response, String namespace, String actionName, Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap) {
HashMap extraContext = createContextMap(requestMap, parameterMap, sessionMap, applicationMap, request, response, getServletConfig());
extraContext.put(SERVLET_DISPATCHER, this);


// If there was a previous value stack, then create a new copy and pass it in to be used by the new Action
OgnlValueStack stack = (OgnlValueStack) request.getAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY);
if (stack != null) {
extraContext.put(ActionContext.VALUE_STACK,new OgnlValueStack(stack));
}
try {
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);
}
}


方法createContextMap执行数据的包装:


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;
}


众所周知,不仅WebWork能使用XWork,而且还可以有类似的FtpWork,MailWork,JMSWork能够替代WebWork来使用Xwork,为什么能够这样,因为Xwork的使用方式.在上面的serviceAction方法中:


ActionProxy proxy = ActionProxyFactory.getFactory().createActionProxy(namespace, actionName, extraContext);
request.setAttribute(ServletActionContext.WEBWORK_VALUESTACK_KEY, proxy.getInvocation().getStack());
proxy.execute();
这些代码就是这种方式的体现:动作代理-动作调用-具体的动作.为使客户代码不绑定到特定代理,XWork使用了一个工厂模式,提供工厂类 ActionProxyFactory.


方法createActionProxy实际调用导致一个ActionProxy接口的缺省实现DefaultActionProxy被实例化:


它的构造器是:


protected ActionInvocation invocation;


protected DefaultActionProxy(String namespace, String actionName, Map extraContext, boolean executeResult) throws Exception {
if (LOG.isDebugEnabled()) {
LOG.debug("Creating an DefaultActionProxy for namespace " + namespace + " and action name " + actionName);
}

this.actionName = actionName;
this.namespace = namespace;
this.executeResult = executeResult;
this.extraContext = extraContext;

config = ConfigurationManager.getConfiguration().getRuntimeConfiguration().getActionConfig(namespace, actionName);

if (config == null) {
String message;

throw new ConfigurationException(message);
}

prepare();
}


protected void prepare() throws Exception {


//创建ActionInvocation 实例化的仍然是由代理工厂类的工厂方法进行,实例化该接口的缺省 实现DefaultActionInvocation.


invocation = ActionProxyFactory.getFactory().createActionInvocation(this, extraContext);
}


下面是proxy.execute()的细节:

public String execute() throws Exception {
ActionContext nestedContext = ActionContext.getContext();
ActionContext.setContext(invocation.getInvocationContext());

String retCode = null;

try {

retCode = invocation.invoke();
} finally {

ActionContext.setContext(nestedContext);
}

return retCode;

}

最后,看看这个类: DefaultActionInvocation类的invoke方法是如何处理extraContext,先看初始化过程,从构造器开始:

protected DefaultActionInvocation(ActionProxy proxy, Map extraContext, boolean pushAction) throws Exception {

this.proxy = proxy;

this.extraContext = extraContext;

this.pushAction = pushAction;

init();

}

方法init定义,把extraContext转换到invocationContext中,并获得拦截器清单.


private void init() throws Exception {

Map contextMap = createContextMap();

createAction();


if (pushAction) {

stack.push(action);

}

invocationContext = new ActionContext(contextMap);

invocationContext.setName(proxy.getActionName());

List interceptorList = new ArrayList(proxy.getConfig().getInterceptors());

interceptors = interceptorList.iterator();

}

在下面这个方法中获得动作上下文contextMap,并把extraContext包含其中.

protected Map createContextMap() {

Map contextMap;

if ((extraContext!=null)&& (extraContext.containsKey(ActionContext.VALUE_STACK))) {

// In case the ValueStack was passed in

stack = (OgnlValueStack) extraContext.get(ActionContext.VALUE_STACK);

if (stack == null) {

throw new IllegalStateException("There was a null Stack set into the extra params.");

}

contextMap = stack.getContext();

} else {

// create the value stack

// this also adds the ValueStack to its context

stack = new OgnlValueStack();

// create the action context

contextMap = stack.getContext();

}

// put extraContext in

if (extraContext != null) {

contextMap.putAll(extraContext);

}

//put this DefaultActionInvocation into the context map

contextMap.put(ActionContext.ACTION_INVOCATION, this);

return contextMap;

}

protected void createAction() {

// load action

try {

action = ObjectFactory.getObjectFactory().buildAction(proxy.getConfig());

} catch (InstantiationException e) {

throw new XworkException("Unable to intantiate Action!", e);

} catch (IllegalAccessException e) {

throw new XworkException("Illegal access to constructor, is it public?", e);

} catch (ClassCastException e) {

throw new XworkException("Action class " + proxy.getConfig().getClassName() + " does not implement " + Action.class.getName(), e);

} catch (Exception e) {

String gripe = "";


if (proxy == null) {

gripe = "Whoa! No ActionProxy instance found in current ActionInvocation. This is bad ... very bad";

} else if (proxy.getConfig() == null) {

gripe = "Sheesh. Where'd that ActionProxy get to? I can't find it in the current ActionInvocation!?";

} else if (proxy.getConfig().getClassName() == null) {

gripe = "No Action defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";

} else {

gripe = "Unable to instantiate Action, " + proxy.getConfig().getClassName() + ", defined for '" + proxy.getActionName() + "' in namespace '" + proxy.getNamespace() + "'";

}


gripe += (((" -- " + e.getMessage()) != null) ? e.getMessage() : " [no message in exception]");

throw new XworkException(gripe, e);

}

}

初始化结束了, 接下来看看invocation.invoke()到底做了什么:


public String invoke() throws Exception {

if (executed) {

throw new IllegalStateException("Action has already executed");

}

if (interceptors.hasNext()) {

Interceptor interceptor = (Interceptor) interceptors.next();

在这个类中,并没有调用getResult(),因为这个方法是由某些拦截器调用的,例如: ExecuteAndWaitInterceptor, TokenSessionStoreInterceptor,如果自己需要,也可以创建自己的拦截器,并在其中访问它.


通过Interceptor接口中的String intercept(ActionInvocation invocation) throws Exception可以看到, 参数invocation已经携带了所有能处理的数据了.


resultCode = interceptor.intercept(this);


} else {

resultCode = invokeAction(getAction(), proxy.getConfig());


}

if (!executed) {

if (preResultListeners != null) {

for (Iterator iterator = preResultListeners.iterator();

iterator.hasNext();) {

PreResultListener listener = (PreResultListener) iterator.next();

listener.beforeResult(this, resultCode);

}

}

now execute the result, if we're supposed to,如果不期望执行Result,那么在代理中设置proxy.getExecuteResult(false)即可,有时候是需要这样的,如TokenSessionStoreInterceptor;


if (proxy.getExecuteResult()) {

executeResult();


}

executed = true;


}

return resultCode;

}


在这个方法中,调用了Result接口的方法execute(ActionInvocation),当该方法返回时一个请求响应回合就完成了.


private void executeResult() throws Exception {

result = createResult();

if (result != null) {

result.execute(this);


} else if (!Action.NONE.equals(resultCode)) {

LOG.warn("No result defined for action " + getAction().getClass().getName() + " and result " + getResultCode());

}

}

public Result createResult() throws Exception {

Map results = proxy.getConfig().getResults();

ResultConfig resultConfig = (ResultConfig) results.get(resultCode);

Result newResult = null;


if (resultConfig != null) {

try {

newResult = ObjectFactory.getObjectFactory().buildResult(resultConfig);

} catch (Exception e) {

LOG.error("There was an exception while instantiating the result of type " + resultConfig.getClassName(), e);

throw e;

}

}

return newResult;

}


public Result getResult() throws Exception {

Result returnResult = result;

// If we've chained to other Actions, we need to find the last result

while (returnResult instanceof ActionChainResult) {

ActionProxy aProxy = ((ActionChainResult) returnResult).getProxy();

if (aProxy != null) {

Result proxyResult = aProxy.getInvocation().getResult();

if ((proxyResult != null) && (aProxy.getExecuteResult())) {

returnResult = proxyResult;

} else {

break;

}

} else {

break;

}

}

return returnResult;

}


protected String invokeAction(Action action, ActionConfig actionConfig) throws Exception {

if (proxy.getConfig().getMethodName() == null) {

return getAction().execute();

} else {

if (LOG.isDebugEnabled()) {

LOG.debug("Executing action method = " + actionConfig.getMethodName());

}

try {

Method method = actionConfig.getMethod(action.getClass());

if (action instanceof Proxy) {

try {

return (String) Proxy.getInvocationHandler(action).invoke(action, method, new Object[0]);

} catch (Throwable throwable) {

throwable.printStackTrace();

throw new Exception("Error invoking on proxy: " + throwable.getMessage());

}

} else {

return (String) method.invoke(action, new Object[0]);

}

} catch (NoSuchMethodException e) {

throw new IllegalArgumentException("Method '" + actionConfig.getMethodName() + "()' is not defined in action '" + getAction().getClass() + "'");

} catch (InvocationTargetException e) {

// We try to return the source exception.

Throwable t = e.getTargetException();

if (t instanceof Exception) {

throw (Exception) t;

} else {

throw e;

}

}

}

}

}


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/keepeye/archive/2005/06/16/390257.aspx
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值