Dispatcher类
Dispatcher类是在struts2中定义的,在 webwork2 中叫DispatcherUtils,
作用相同:
1 初始化模块参数,
2 将 xwork 于 web层分离,
3 中转请求,进入xwork 的 action处理流程。
1 初始化,涉及方法 init()
在上一篇的 FilterDispatcher中的init() 方法,有这么两句:
- dispatcher = createDispatcher(filterConfig);
- dispatcher.init();
就是调用Dispatcher的初始化。
2 xwork 定义了一个类 : ActonContext,
ActonContext 有两个作用
1) 线程安全,
过这个类,xwork2 实现了 action 的线程安全,
为每一次的action请求, 分配一个独立的ActonContext。
2) 于 web 层分离,
xwork的做法,是把web层中组件中的变量
(主要是javax.servlet包中的类,如HttpServletRequest)
取出来,放入ActonContext。
这样xwork就不要在向外访问web层了。
涉及方法
- public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response,
- ActionMapping mapping, ServletContext context) {
Dispatcher 的这个方法,把web层的参数取出然后放入Map 中,(以备xwork构造ActionContext)。
3 中转请求,调action处理逻辑,这个是比较重要的一个地方,
- public void serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,
- ActionMapping mapping) throws ServletException {
- Map<String, Object> extraContext = createContextMap(request, response, mapping, context);
- // 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);
- if (stack != null) {
- extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack));
- }
- String timerKey = "Handling request from Dispatcher";
- try {
- UtilTimerStack.push(timerKey);
- String namespace = mapping.getNamespace();
- String name = mapping.getName();
- String method = mapping.getMethod();
- Configuration config = configurationManager.getConfiguration();
- ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
- namespace, name, extraContext, true, false);
- proxy.setMethod(method);
- 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 {
- proxy.execute();
- }
- // If there was a previous value stack then set it back onto the request
- if (stack != null) {
- request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack);
- }
- } catch (ConfigurationException e) {
- LOG.error("Could not find action or result", e);
- sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e);
- } catch (Exception e) {
- throw new ServletException(e);
- } finally {
- UtilTimerStack.pop(timerKey);
- }
- }
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 负责框架配置信息初始化的类
- public class DefaultConfiguration implements Configuration {
- protected static final Logger LOG = LoggerFactory.getLogger(DefaultConfiguration.class);
- // Programmatic Action Configurations
- protected Map<String, PackageConfig> packageContexts = new LinkedHashMap<String, PackageConfig>();
- protected RuntimeConfiguration runtimeConfiguration;
- protected Container container;
- protected String defaultFrameworkBeanName;
- protected Set<String> loadedFileNames = new TreeSet<String>();
- ObjectFactory objectFactory;
这是描述框架总体配置信息的,其中,
Map<String, PackageConfig> 放的是package的config,对应struts2 配置文件中 package标签内容,
PackageConfig
- public class PackageConfig extends Located implements Comparable, Serializable, InterceptorLocator {
- private static final Logger LOG = LoggerFactory.getLogger(PackageConfig.class);
- private Map<String, ActionConfig> actionConfigs;
- private Map<String, ResultConfig> globalResultConfigs;
- private Map<String, Object> interceptorConfigs;
- private Map<String, ResultTypeConfig> resultTypeConfigs;
- private List<ExceptionMappingConfig> globalExceptionMappingConfigs;
- private List<PackageConfig> parents;
- private String defaultInterceptorRef;
- private String defaultActionRef;
- private String defaultResultType;
- private String defaultClassRef;
- private String name;
- private String namespace = "";
- private boolean isAbstract = false;
- private boolean needsRefresh;
里边是一些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); retCode = invocation.invoke(); } 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 { resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); return null; } }); } else { resultCode = invokeActionOnly(); } // 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 invokeActionOnly() throws Exception { return invokeAction(getAction(), proxy.getConfig()); } protected 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 { method = getAction().getClass().getMethod(methodName, new Class[0]); } 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) { methodResult = method.invoke(action, new Object[0]); } 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) 的任务之一,
下篇探讨一下拦截器。