Dispatcher类
Dispatcher类是在struts2中定义的,在 webwork2 中叫DispatcherUtils,
作用相同:
1 初始化模块参数,
2 将 xwork 于 web层分离,
3 中转请求,进入xwork 的 action处理流程。
1 初始化,涉及方法 init()
在上一篇的 FilterDispatcher中的init() 方法,有这么两句:
就是调用Dispatcher的初始化。
2 xwork 定义了一个类 : ActonContext,
ActonContext 有两个作用
1) 线程安全,
过这个类,xwork2 实现了 action 的线程安全,
为每一次的action请求, 分配一个独立的ActonContext。
2) 于 web 层分离,
xwork的做法,是把web层中组件中的变量
(主要是javax.servlet包中的类,如HttpServletRequest)
取出来,放入ActonContext。
这样xwork就不要在向外访问web层了。
涉及方法
Dispatcher 的这个方法,把web层的参数取出然后放入Map 中,(以备xwork构造ActionContext)。
3 中转请求,调action处理逻辑,这个是比较重要的一个地方,
Configuration config = configurationManager.getConfiguration();
ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace, name, extraContext, true, false);
得到框架的配置信息,得到框架的Container,构造出 ActionProxy。
这个过程中,涉及到几个xwork较核心的类,Configuration, ConfigurationManager, Container,
Configuration, ConfigurationManager 负责框架配置信息初始化的类
这是描述框架总体配置信息的,其中,
Map<String, PackageConfig> 放的是package的config,对应struts2 配置文件中 package标签内容,
PackageConfig
里边是一些package的信息,其中Map<String, ActionConfig> 放的就是action的描述类ActionConfig了
ActionConfig
- public class ActionConfig extends Located implements Serializable {
- public static final String WILDCARD = "*" ;
- protected List<InterceptorMapping> interceptors;
- protected Map<String, String> params;
- protected Map<String, ResultConfig> results;
- protected List<ExceptionMappingConfig> exceptionMappings;
- protected String className;
- protected String methodName;
- protected String packageName;
- protected String name;
- protected Set<String> allowedMethods;
其中
interceptors : action的拦截器,
results: action执行后用来收尾的,如,跳到定义好的页面。 className 类名,packageName 包名,methodName 默认是 execute。
框架一般有个必须要做的活,就是把某配置文件的信息读到框架系统中来,
xwork2中,XMLConfigurationProvider 就是干这个的,
他读xml配置文件(就是我们定义action的配置的那个文件),
然后把这些信息写到Configuration中。
ConfigurationManager 则负责调用适当的 ConfigurationProvider,
执行初始化逻辑,和返回具体的Configuration。
初始化等前期工作完毕后,则开始执行action的逻辑了,
xwork 使用了代理模式执行action,
proxy.execute();
从这一句起, strust2 就把工作交接给了xwork了。
接着看Dispatcher
- ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory. class ).createActionProxy(
- namespace, name, extraContext, true , false );
- ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory. class ).createActionProxy(
- namespace, name, extraContext, true , false );
用Container 构造一个 ActionProxyFactory,在用ActionProxyFactory create一个 ActionProxy。
- public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext) {
- ActionInvocation inv = new DefaultActionInvocation(extraContext, true );
- container.inject(inv);
- return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
- }
- public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext) {
- ActionInvocation inv = new DefaultActionInvocation(extraContext, true );
- container.inject(inv);
- return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
- }
xwork中,action的调用是借助 Proxy 模式,
Proxy 模式的实现,则是 DefaultActionProxy, Action, ActionInvocation 合伙完成的。
下边是一些关键代码
DefaultActionProxy
- public String execute() throws Exception {
- ActionContext nestedContext = ActionContext.getContext();
- ActionContext.setContext(invocation.getInvocationContext());
- String retCode = null ;
- String profileKey = "execute: " ;
- try {
- UtilTimerStack.push(profileKey);
- <SPAN style= "COLOR: #ff0000" > retCode = invocation.invoke();</SPAN>
- } finally {
- if (cleanupContext) {
- ActionContext.setContext(nestedContext);
- }
- UtilTimerStack.pop(profileKey);
- }
- return retCode;
- }
- public String execute() throws Exception {
- ActionContext nestedContext = ActionContext.getContext();
- ActionContext.setContext(invocation.getInvocationContext());
- String retCode = null ;
- String profileKey = "execute: " ;
- try {
- UtilTimerStack.push(profileKey);
- <span style="color: #ff0000;" > retCode = invocation.invoke();</span>
- } finally {
- if (cleanupContext) {
- ActionContext.setContext(nestedContext);
- }
- UtilTimerStack.pop(profileKey);
- }
- return retCode;
- }
DefaultActionInvocation 得 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();
- UtilTimerStack.profile( "interceptor: " +interceptor.getName(),
- new UtilTimerStack.ProfilingBlock<String>() {
- public String doProfiling() throws Exception {
- <SPAN style= "COLOR: #ff0000" >resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation. this );</SPAN>
- return null ;
- }
- });
- } else {
- <SPAN style= "COLOR: #ff0000" >resultCode = invokeActionOnly();</SPAN>
- }
- // 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 (Iterator iterator = preResultListeners.iterator();
- iterator.hasNext();) {
- PreResultListener listener = (PreResultListener) iterator.next();
- 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);
- }
- }
- 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();
- UtilTimerStack.profile("interceptor: " +interceptor.getName(),
- new UtilTimerStack.ProfilingBlock<String>() {
- public String doProfiling() throws Exception {
- <span style="color: #ff0000;" >resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation. this );</span>
- return null ;
- }
- });
- } else {
- <span style="color: #ff0000;" >resultCode = invokeActionOnly();</span>
- }
- // 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 (Iterator iterator = preResultListeners.iterator();
- iterator.hasNext();) {
- PreResultListener listener = (PreResultListener) iterator.next();
- 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);
- }
- }
resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); 是判断这个action是否有未被执行的拦截器,
resultCode = invokeActionOnly();
如没有或拦截器执行完毕,则执行invokeActionOnly
invokeActionOnly方法
- public String <SPAN style= "COLOR: #ff0000" >invokeActionOnly()</SPAN> throws Exception {
- return invokeAction(getAction(), proxy.getConfig());
- }
- rotected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
- String methodName = proxy.getMethod();
- if (LOG.isDebugEnabled()) {
- LOG.debug( "Executing action method = " + actionConfig.getMethodName());
- }
- String timerKey = "invokeAction: " +proxy.getActionName();
- try {
- UtilTimerStack.push(timerKey);
- boolean methodCalled = false ;
- Object methodResult = null ;
- Method method = null ;
- try {
- <SPAN style= "COLOR: #ff0000" >method = getAction().getClass().getMethod(methodName, new Class[ 0 ]);</SPAN>
- } catch (NoSuchMethodException e) {
- // hmm -- OK, try doXxx instead
- try {
- String altMethodName = "do" + methodName.substring( 0 , 1 ).toUpperCase() + methodName.substring( 1 );
- method = getAction().getClass().getMethod(altMethodName, new Class[ 0 ]);
- } catch (NoSuchMethodException e1) {
- // well, give the unknown handler a shot
- if (unknownHandler != null ) {
- try {
- methodResult = unknownHandler.handleUnknownActionMethod(action, methodName);
- methodCalled = true ;
- } catch (NoSuchMethodException e2) {
- // throw the original one
- throw e;
- }
- } else {
- throw e;
- }
- }
- }
- if (!methodCalled) {
- <SPAN style= "COLOR: #ff0000" >methodResult = method.invoke(action, new Object[ 0 ]);</SPAN>
- }
- if (methodResult instanceof Result) {
- this .explicitResult = (Result) methodResult;
- return null ;
- } else {
- return (String) methodResult;
- }
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException( "The " + methodName + "() is not defined in action " + getAction().getClass() + "" );
- } catch (InvocationTargetException e) {
- // We try to return the source exception.
- Throwable t = e.getTargetException();
- if (actionEventListener != null ) {
- String result = actionEventListener.handleException(t, getStack());
- if (result != null ) {
- return result;
- }
- }
- if (t instanceof Exception) {
- throw (Exception) t;
- } else {
- throw e;
- }
- } finally {
- UtilTimerStack.pop(timerKey);
- }
- }
- public String <span style= "color: #ff0000;" >invokeActionOnly()</span> throws Exception {
- return invokeAction(getAction(), proxy.getConfig());
- }
- rotected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
- String methodName = proxy.getMethod();
- if (LOG.isDebugEnabled()) {
- LOG.debug("Executing action method = " + actionConfig.getMethodName());
- }
- String timerKey = "invokeAction: " +proxy.getActionName();
- try {
- UtilTimerStack.push(timerKey);
- boolean methodCalled = false ;
- Object methodResult = null ;
- Method method = null ;
- try {
- <span style="color: #ff0000;" >method = getAction().getClass().getMethod(methodName, new Class[ 0 ]);</span>
- } catch (NoSuchMethodException e) {
- // hmm -- OK, try doXxx instead
- try {
- String altMethodName = "do" + methodName.substring( 0 , 1 ).toUpperCase() + methodName.substring( 1 );
- method = getAction().getClass().getMethod(altMethodName, new Class[ 0 ]);
- } catch (NoSuchMethodException e1) {
- // well, give the unknown handler a shot
- if (unknownHandler != null ) {
- try {
- methodResult = unknownHandler.handleUnknownActionMethod(action, methodName);
- methodCalled = true ;
- } catch (NoSuchMethodException e2) {
- // throw the original one
- throw e;
- }
- } else {
- throw e;
- }
- }
- }
- if (!methodCalled) {
- <span style="color: #ff0000;" >methodResult = method.invoke(action, new Object[ 0 ]);</span>
- }
- if (methodResult instanceof Result) {
- this .explicitResult = (Result) methodResult;
- return null ;
- } else {
- return (String) methodResult;
- }
- } catch (NoSuchMethodException e) {
- throw new IllegalArgumentException( "The " + methodName + "() is not defined in action " + getAction().getClass() + "" );
- } catch (InvocationTargetException e) {
- // We try to return the source exception.
- Throwable t = e.getTargetException();
- if (actionEventListener != null ) {
- String result = actionEventListener.handleException(t, getStack());
- if (result != null ) {
- return result;
- }
- }
- if (t instanceof Exception) {
- throw (Exception) t;
- } else {
- throw e;
- }
- } finally {
- UtilTimerStack.pop(timerKey);
- }
- }
method = getAction().getClass().getMethod(methodName, new Class[0]); 取出需执行的action的方法,如 execute()
methodResult = method.invoke(action, new Object[0]); 利用反射,执行action 方法
上边就是利用proxy模式,调用一个action的具体逻辑 的 过程。
一般的action里,都有一些变量,如从request中取出的参数等,
如要执行action 方法,如execute(),则必须先吧这些变量赋值 已供方法中使用,
这个工作,就是 拦截器(Interceptor) 的任务之一,
下篇探讨一下拦截器。