struts2执行流程

写在前面:struts2在web应用层面属于表示层框架,在MVC开发模式中属于C(Controller控制器),负责对M(Model模型)和V(View视图)进行解耦。struts2是在struts1和webwork的技术基础上进行了合并的全新的框架。struts2虽然和struts1在名字上很相似,但是却不是后者的升级版。struts2其实是以另一个表示层框架webwork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以struts2也可以理解为webwork的更新产品。从它们的处理请求的执行流程就可以看出相似点。

直观感受一下:

webwork:
这里写图片描述

struts2:

这里写图片描述

struts2和webwork都是通过一个FilterDispatcher过滤器来匹配客户端发送的所有请求(当然,现在struts2的过滤器名是StrutsPreparedAndExecuteFilter),不同于struts1是通过一个servlet来匹配所有请求,好了,这里先简单的了解一下struts2和struts1的区别, 在文章末尾会详细的介绍struts2和struts1的区别,开始进入主题。

struts2的执行流程(结合流程图分析):

  1. 客户端发送一个HTTP请求

  2. 该请求被struts2的核心过滤器StrutsPreparedAndExecuteFilter匹配(只要是在过滤器的url-pattern中配置了/*,那么任何请求都会进入该过滤器,无论该请求是否需要struts2来处理),当然,在进入这个过滤器之前会依次进入在web.xml中配置的位置在struts2过滤器之前的其他Filter或Servlet

  3. struts2的过滤器会询问(形象一点的说法,其实就是调用方法)ActionMapper该请求是否有与之对应的业务控制类,如果没有,则放行,如果有,进入下一步执行流程

  4. struts2通过ActionProxy实例化ActionInvocation,当然在这之前ActionProxy还会通过ConfigurationManager按序加载struts2的配置文件:default.properties, struts-default.xml, struts.properties, struts.xml…(先加载struts默认的,然后才是自己定义的),正是因为加载了这些配置文件所以struts才能找到相应的拦截器以及业务控制类。

  5. ActionProxy初始化一个ActionInvocation并通过它的invoke来正式执行一系列的拦截器以及Action,在执行完Action之后会根据使用的模板(jsp, velocity, freemarker…)组装结果集Result,渲染页面

  6. 返回给客户端响应

接下来详细的分析一下:

1. 客户端发送一个HTTP请求

可能是一个登陆请求,也可能是查询某个功能列表的请求...

2. StrutsPreparedAndExecuteFilter过滤器拦截该请求

过滤器拦截到该请求的时候会调用doFilter方法,如下:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
   
	// 1.将ServletRequest和ServletResponse对象转换为HttpServletRequest和HttpServletResponse对象
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    try {
   
	    // 2.对不由struts2处理的请求放行,这个excludedPatterns是一个List<Pattern>集合,里面存储了不被struts2的过滤器匹配的url
        if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
   
            chain.doFilter(request, response);
        } else {
   
	        // 3.设置请求和相应的编码以及国际化的相关信息
            prepare.setEncodingAndLocale(request, response);
            // 4.创建一个Action的上下文,并初始化一个本地线程
            // 源码注释:Creates the action context and initializes the thread local
            prepare.createActionContext(request, response);
            // 5.把dispatcher指派给本地线程
            // 源码注释:Assigns the dispatcher to the dispatcher thread local
            prepare.assignDispatcherToThread();
            // 6.包装一下request防止它是一个multipart/form-data类型的请求
            // 源码注释:Wrap request first, just in case it is multipart/form-data
            request = prepare.wrapRequest(request);
            // 7.查找ActionMapping信息(包括name,namespace,method,extention,params,result)
            ActionMapping mapping = prepare.findActionMapping(request, response, true);
            // 8.没有找到请求对应的业务控制类
            if (mapping == null) {
   
                boolean handled = execute.executeStaticResourceRequest(request, response);
                if (!handled) {
   
                    chain.doFilter(request, response);
                }
            } else {
   
            // 9.找到了对应的业务控制类那就去执行该Action
                execute.executeAction(request, response, mapping);
            }
        }
    } finally {
   
	    // 10.释放掉这个Request所占用的一些内存空间
        prepare.cleanupRequest(request);
    }
}
2.1. 首先将ServletRequest和ServletResponse对象转换为HttpServletRequest和HttpServletResponse对象
2.2. 判断是否设置了不被struts2过滤器拦截的请求
if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
   
	chain.doFilter(request, response);
}

这个excludedPatterns是一个List< Pattern >集合,里面包含了不被struts2过滤器拦截的url。看这一句:prepare.isUrlExcluded(request, excludedPatterns),判断这个请求里面是否包含这样的url,跟进源码查看一具体的实现:

public boolean isUrlExcluded( HttpServletRequest request, List<Pattern> excludedPatterns ) {
   
    if (excludedPatterns != null) {
   
	    // 1.获取当前请求中的uri
        String uri = RequestUtils.getUri(request);
        // 2.查看集合中是否有与之匹配的,有就返回true
        for ( Pattern pattern : excludedPatterns ) {
   
            if (pattern.matcher(uri).matches()) {
   
                return true;
            }
        }
    }
    return false;
}

知道了拦截器是通过excludedPatterns来判断哪个url不被拦截,那么这个excludedPatterns的值是从哪里来的呢?初步猜测是在StrutsPreparedAndExecuteFilter初始化(init)的时候设置的…果不其然,看源码:

public void init(FilterConfig filterConfig) throws ServletException {
   
    InitOperations init = new InitOperations();
    Dispatcher dispatcher = null;
    try {
   
        FilterHostConfig config = new FilterHostConfig(filterConfig);
        init.initLogging(config);
        dispatcher = init.initDispatcher(config);
        init.initStaticContentLoader(config, dispatcher);

        prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);
        execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);
        // 就是这里,创建了不匹配的url列表
        this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

        postInit(dispatcher, filterConfig);
    } finally {
   
        if (dispatcher != null) {
   
            dispatcher.cleanUpAfterInit();
        }
        init.cleanup();
    }
}

跟进buildExcludedPatternsList方法:

public List<Pattern> buildExcludedPatternsList( Dispatcher dispatcher ) {
   
	// 由此可知是struts2是读取了STRUTS_ACTION_EXCLUDE_PATTERN常量的值来判断哪些请求不需要匹配
    return buildExcludedPatternsList(dispatcher.getContainer().getInstance(String.class, StrutsConstants.STRUTS_ACTION_EXCLUDE_PATTERN));
}
        
private List<Pattern> buildExcludedPatternsList( String patterns ) {
   
    if (null != patterns && patterns.trim().length() != 0) {
   
        List<Pattern> list = new ArrayList<Pattern>();
        String[] tokens = patterns.split(",");
        for ( String token : tokens ) {
   
      
  • 16
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值