本文剖析的源码波及三个方面:

1  struts中应用到的动静代理:ActionProxy 和 ActionInvocation

2  struts中是如何解决拦截器和action申请的

3  struts中是如何处理结果的

每个申请都会通过Dispatcher中的serviceAction办法,这个办法中有很重要的一句代码

String namespace = mapping.getNamespace();String name = mapping.getName();String method = mapping.getMethod();//步骤1 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!//  前面再剖析resultif (mapping.getResult() != null) {    Result result = mapping.getResult();    result.execute(proxy.getInvocation());} else {    // 步骤2     proxy.execute();}

这外面比拟重要的一句是获取proxy的这一句,从container中先获取一个ActionProxyFactory的实例,而后依据命名空间(struts.xml的package?),action的名字,办法名,上下文生成一个ActionProxy,理论是ActionProxy执行了action。

ActionProxyFactory如何创立ActionProxy?

ActionProxyFactory是一个接口,默认的工厂类是DefaultActionProxyFactory,其中的createActionProxy办法如下:

public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map<String, Object> extraContext, boolean executeResult, boolean cleanupContext) {    //  创立了一个ActionInvocation实例    ActionInvocation inv = createActionInvocation(extraContext, true);    container.inject(inv);    // 通过上面的createActionProxy可知ActionProxy中持有了对ActionInvocation的援用    return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);} protected ActionInvocation createActionInvocation(Map<String, Object> extraContext, boolean pushAction) {    return new DefaultActionInvocation(extraContext, pushAction);} public ActionProxy createActionProxy(ActionInvocation inv, String namespace, String actionName, String methodName, boolean executeResult, boolean cleanupContext) {    //  传进去的inv会在prepare的时候用到    DefaultActionProxy proxy = new DefaultActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);    container.inject(proxy);    // 有一些初始化操作,比方methodname是null的时候就默认执行execute办法    proxy.prepare();    return proxy;}

在下面的proxy.prepare 中,除了会对methodname有解决,还有重要的一步是invocation.init(this),这里的invocation就是new DefaultActionProxy的时候传入的inv,上面看看DefaultActionInvocation中的init会做些什么

public void init(ActionProxy proxy) {    // 可见actionInvocation中也持有一个actionProxy的援用    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也有一个对actioninvocation的援用        actionContext.setActionInvocation(this);    }    //  创立action实例    createAction(contextMap);    if (pushAction) {        stack.push(action);        contextMap.put("action", action);    }    invocationContext = new ActionContext(contextMap);    invocationContext.setName(proxy.getActionName());    //创立相干拦截器    createInterceptors(proxy);} //具体看下actioninvocation是如何创立一个action的protected void createAction(Map<String, Object> contextMap) {    // load action    String timerKey = "actionCreate: " + proxy.getActionName();    try {        UtilTimerStack.push(timerKey);        // actioninvocation中有一个action的全局变量        // 次要就是这一句,这里用到了objectfactory,这个工厂类持有对actionfactory的援用,理论是调用了actionfactory的buildaction        // todo actionfactory的buildaction  前面再具体看actionfactory        action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap);    } catch (InstantiationException e) {        throw new XWorkException("Unable to intantiate Action!", e, proxy.getConfig());    } catch (IllegalAccessException e) {        throw new XWorkException("Illegal access to constructor, is it public?", e, proxy.getConfig());    } 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, proxy.getConfig());    } finally {        UtilTimerStack.pop(timerKey);    }    if (actionEventListener != null) {        action = actionEventListener.prepare(action, stack);    }} //创立拦截器就比较简单了,依据配置文件把所有的拦截器放在一个list中protected void createInterceptors(ActionProxy proxy) {    // 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();}

理一下后面的:

dispatcher中先创立了actionproxy,同时会创立一个actioninvocation,而后对methodname对解决,创立action实例,创立拦截器list。

到目前为止,dispatcher中的步骤1 实现。当初开始步骤2,步骤2就是具体的要执行action的execute办法。

DefaultActionProxy的execute代码如下

public String execute() throws Exception {    //context  相干后续剖析    ActionContext nestedContext = ActionContext.getContext();    ActionContext.setContext(invocation.getInvocationContext());    String retCode = null;    String profileKey = "execute: ";    try {        UtilTimerStack.push(profileKey);        //  proxy中应用invocation实现action的执行,和java的动静代理是一样的        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");        }        //  这里的interceptors 类型是Iterator<InterceptorMapping>,就是下面createInterceptors的时候被赋值的        //  遍历interceptors        if (interceptors.hasNext()) {            final InterceptorMapping interceptor = interceptors.next();            String interceptorMsg = "interceptor: " + interceptor.getName();            UtilTimerStack.push(interceptorMsg);            try {                  // 每拿到一个拦截器,就执行拦截器的intercept办法,在拦截器的intercept办法中肯定会执行incovation.invoke,就会又调到本办法中                  // 联合这里,就可能晓得拦截器的执行程序,每个拦截器执行到invocation.invoke之后都会递归的调到下一个拦截器上                  // 假如有三个拦截器A B C,把每个拦截器在invocation.invoke前的代码成为invoke前,之后的代码成为invoke后                  // 执行程序就是:A的invoke前,B的invoke前,c的invoke前,action,c的invoke后,B的invoke后,A的invoke后                  resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);            }            finally {                UtilTimerStack.pop(interceptorMsg);            }        } else {            // 拦截器链中最初一个拦截器的invation.invoke就会执行action自身            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) {                LOG.trace("Executing PreResultListeners for result [#0]", result);                for (Object preResultListener : preResultListeners) {                    PreResultListener listener = (PreResultListener) preResultListener;                    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 invokeActionOnly() throws Exception {    //  这里的getaction办法就是invocation持有的action实例,即在后面创立action实例的时候创立的    return invokeAction(getAction(), proxy.getConfig());}

上面看一下invokeAction办法中是怎么执行action的:

protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {    // 获取要执行办法名,是否有必要应用默认的execute也早在proxy的prepare中解决过了    String methodName = proxy.getMethod();    if (LOG.isDebugEnabled()) {        LOG.debug("Executing action method = #0", methodName);    }    String timerKey = "invokeAction: " + proxy.getActionName();    try {        UtilTimerStack.push(timerKey);        Object methodResult;        try {            //应用onglUtil这个工具类执行action的办法,具体的就要理解onglutil做了啥了。。            methodResult = ognlUtil.callMethod(methodName + "()", getStack().getContext(), action);        } catch (MethodFailedException e) {            // if reason is missing method, try find version with "do" prefix            if (e.getReason() instanceof NoSuchMethodException) {                try {                    String altMethodName = "do" + methodName.substring(0, 1).toUpperCase() + methodName.substring(1) + "()";                    methodResult = ognlUtil.callMethod(altMethodName, getStack().getContext(), action);                } catch (MethodFailedException e1) {                    // if still method doesn't exist, try checking UnknownHandlers                    if (e1.getReason() instanceof NoSuchMethodException) {                        if (unknownHandlerManager.hasUnknownHandlers()) {                            try {                                methodResult = unknownHandlerManager.handleUnknownMethod(action, methodName);                            } catch (NoSuchMethodException e2) {                                // throw the original one                                throw e;                            }                        } else {                            // throw the original one                            throw e;                        }                        // throw the original exception as UnknownHandlers weren't able to handle invocation as well                        if (methodResult == null) {                            throw e;                        }                    } else {                        // exception isn't related to missing action method, throw it                        throw e1;                    }                }            } else {                // exception isn't related to missing action method, throw it                throw e;            }        }        // 解决执行完办法后拿到的methodResult,而后返回解决后的后果        return saveResult(actionConfig, methodResult);    } catch (NoSuchPropertyException e) {        throw new IllegalArgumentException("The " + methodName + "() is not defined in action " + getAction().getClass() + "");    } catch (MethodFailedException e) {        // We try to return the source exception.        Throwable t = e.getCause();        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);    }}

saveReult:

// 如果methodresult是Result类型就保留到explicitResult(explicitResult是actioninvocation中一个Rsult类型的全局变量)上,返回null,否则间接返回string的methodResultprotected String saveResult(ActionConfig actionConfig, Object methodResult) {    if (methodResult instanceof Result) {        this.explicitResult = (Result) methodResult;        // Wire the result automatically        container.inject(explicitResult);        return null;    } else {        return (String) methodResult;    }}

再回到invoke中,执行完action之后有一段代码

// now execute the result, if we're supposed toif (proxy.getExecuteResult()) {    executeResult();} // 具体的executeResult如下private void executeResult() throws Exception {    // create a Result    result = createResult();    String timerKey = "executeResult: " + getResultCode();    try {        UtilTimerStack.push(timerKey);        if (result != null) {            // 执行Result的execute            result.execute(this);        } else if (resultCode != null && !Action.NONE.equals(resultCode)) {            throw new ConfigurationException("No result defined for action " + getAction().getClass().getName()                    + " and result " + getResultCode(), proxy.getConfig());        } else {            if (LOG.isDebugEnabled()) {                LOG.debug("No result returned for action " + getAction().getClass().getName() + " at " + proxy.getConfig().getLocation());            }        }    } finally {        UtilTimerStack.pop(timerKey);    }} //具体的createResult如下public Result createResult() throws Exception {    LOG.trace("Creating result related to resultCode [#0]", resultCode);    if (explicitResult != null) {        把之前在saveResult中保留到explicitResult中的值赋值到ret中,同时explicitResult清空        Result ret = explicitResult;        explicitResult = null;        // 如果explicitResult不为空,即之前取得的后果间接就是一个result类型,那么间接返回        // 否则之前取得后果是一个一般的字符串,须要找到字符串对应的Result        return ret;    }        ActionConfig config = proxy.getConfig();    // 配置文件中配置的result节点信息    Map<String, ResultConfig> results = config.getResults();    ResultConfig resultConfig = null;    try {        //  尝试获取resultCode对应的resultconfig        resultConfig = results.get(resultCode);    } catch (NullPointerException e) {        if (LOG.isDebugEnabled()) {            LOG.debug("Got NPE trying to read result configuration for resultCode [#0]", resultCode);        }    }    if (resultConfig == null) {        // If no result is found for the given resultCode, try to get a wildcard '*' match.        resultConfig = results.get("*");    }    if (resultConfig != null) {        try {            // 依据resultconfig 结构一个Result返回            return objectFactory.buildResult(resultConfig, invocationContext.getContextMap());        } catch (Exception e) {            if (LOG.isErrorEnabled()) {                LOG.error("There was an exception while instantiating the result of type #0", e, resultConfig.getClassName());            }            throw new XWorkException(e, resultConfig);        }    } else if (resultCode != null && !Action.NONE.equals(resultCode) && unknownHandlerManager.hasUnknownHandlers()) {        return unknownHandlerManager.handleUnknownResult(invocationContext, proxy.getActionName(), proxy.getConfig(), resultCode);    }    return null;}

那么,Result到底是什么?

// Result接口很简略,只提供一个execute办法public interface Result extends Serializable {    /**     * Represents a generic interface for all action execution results.     * Whether that be displaying a webpage, generating an email, sending a JMS message, etc.     *     * @param invocation  the invocation context.     * @throws Exception can be thrown.     */    public void execute(ActionInvocation invocation) throws Exception;}

struts在配置action的时候,会相应的配置result节点,其中包含result的type,每一个type其实对应一个具体的Result实现类,下面的objectFactory.buildResult实则调的是resultFactory的buildResult。

默认的ResultFactory是StrutsResultFactory

public Result buildResult(ResultConfig resultConfig, Map<String, Object> extraContext) throws Exception {    // config中有配置type,找到对应的具体result实现类    String resultClassName = resultConfig.getClassName();    Result result = null;    if (resultClassName != null) {        //  生成具体result实现类的实例        // 回到下面的result.execute,就可晓得这个时候获取了result实例,不同type的result的execute有不同的解决        result = (Result) objectFactory.buildBean(resultClassName, extraContext);        Map<String, String> params = resultConfig.getParams();        if (params != null) {            setParameters(extraContext, result, params);        }    }    return result;}

至此,大略晓得了struts的动静代理的应用,如何用动静代理模式解决action申请和拦截器,如何解决result。

todo:

1  下面只是大略流程,可找几点具体分析

2  context相干

3 struts的工厂类 ObjectFactory及具体的各种工厂类

4 msite当初应用的json result是如何解决的。