基于Struts2.5.16的调用过程

引用一张Struts2调用的时序图:

1.用户发送请求;这个请求被交给你在web.xml文件配置的过滤器(Filter)struts2的过滤器(StrutsPrepareAndExecuteFilter)一般都是在最后一个。调用doFilter方法。

    <filter-mapping>  
        <filter-name>userLoginFilter</filter-name>  
        <url-pattern>/*</url-pattern>  
    </filter-mapping> 

	<!-- 配置struts2的核心拦截器,官方推出用StrutsPreparedAndExcuteFilter代替FilterDispatcher -->
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>*.action</url-pattern>
	</filter-mapping>

StrutsPrepareAndExecuteFilter的doFiler方法:

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            String uri = RequestUtils.getUri(request);
            if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
                LOG.trace("Request {} is excluded from handling by Struts, passing request to other filters", uri);
                chain.doFilter(request, response);
            } else {
                LOG.trace("Checking if {} is a static resource", uri);
                boolean handled = execute.executeStaticResourceRequest(request, response);
                if (!handled) {
                    LOG.trace("Assuming uri {} as a normal action", uri);
                    prepare.setEncodingAndLocale(request, response);
                    prepare.createActionContext(request, response);
                    prepare.assignDispatcherToThread();
                    request = prepare.wrapRequest(request);
                    ActionMapping mapping = prepare.findActionMapping(request, response, true);
                    if (mapping == null) {
                        LOG.trace("Cannot find mapping for {}, passing to other filters", uri);
                        chain.doFilter(request, response);
                    } else {
                        LOG.trace("Found mapping {} for {}", mapping, uri);
                        execute.executeAction(request, response, mapping);
                    }
                }
            }
        } finally {
            prepare.cleanupRequest(request);
        }
    }

2. 调用PrepareOperations的findActionMapping(request, response, true),以便确定这个请求是否有对应的action调用。 返回一个描述action调用的ActionMapping对象 。具体实现类是org.apache.struts2.dispatcher.mapper.DefaultActionMapper的getMapping方法。

    public ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager) {
        ActionMapping mapping = new ActionMapping();
        String uri = RequestUtils.getUri(request);

        int indexOfSemicolon = uri.indexOf(';');
        uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;

        uri = dropExtension(uri, mapping);
        if (uri == null) {
            return null;
        }

        parseNameAndNamespace(uri, mapping, configManager);
        handleSpecialParameters(request, mapping);
        return parseActionName(mapping);
    }

3. ExecuteOperations调用executeAction处理Action。其实质是调用Dispatcher类的serviceAction方法得到一个ActionProxy实例。该方法根据ActionMapping这个对象中的属性以及configurationManager来生成一个ActionProxy。具体实现类是DefaultActionProxyFactory。

            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!
            if (mapping.getResult() != null) {
                Result result = mapping.getResult();
                result.execute(proxy.getInvocation());
            } else {
                proxy.execute();
            }

4. ActionProxy设置ActionInvocation对象的执行上下文,然后调用其invoke方法。从拦截器映射中查找尚未执行的拦截器,调用他的intercept(invocation)方法,并将自身对象引用作为参数传递给拦截器。 

5. 拦截器完成某些预处理工作后,反过来调用ActionInvocation的invoke方法,ActionInvocation维护者自己的状态,所以他知道哪些拦截器已经被执行,如果还没有执行的拦截器,就继续执行他的intercept(invocation)方法。 至所有的拦截器都已经执行过了,就调用action实例的execute方法 。

6. ActionInvocation根据action执行返回的结果码,查找对应的Result,调用Result的execute(invocation)方法,将结果页面呈现给用户。 ActionInvocation的invoke方法将控制权返回给拦截器映射中的最后一个拦截器,该拦截器完成所有必须的后期处理工作,然后从intercept(invocation)方法返回,允许前一个拦截器执行他自己的后处理工作。如此循环到所有的拦截器都成功返回。

7. ActionInvocation的invoke方法执行完毕后,想ActionProxy返回一个String类型的结果码,最后,ActionProxy清理状态并返回。 

ps:关于ActionContext是何时创建的,可以参考下文:

https://blog.csdn.net/u011496144/article/details/74931136

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值