Struts2源码试读1-filter

来源:互联网 发布:兄贵pat it 编辑:程序博客网 时间:2024/05/01 05:11

一直没对struts好好研究过,最近拿出来好好看看。

首先,struts1和struts2还是有很大区别的,鉴于struts1的项目越来越少,就直接跳过。struts2是WebWork的升级版,不过与其这么说不如说struts2是webwork的再封装,让他“看上去”更像struts,但是骨子里却是webwork。

struts属于apache的开源项目,可以直接从http://struts.apache.org/上下载源码包,不过如果想了解更多包括WebWork的内容则需要进一步下载webword的源码包,地址为http://www.opensymphony.com/xwork/download.action。

这边不过多赘述struts2的每个包有什么作用了,从项目运行的开始一步步分析struts2是如何运行并得到结果的。

struts说白了也还是个web项目,所以没什么特别的东西。在我的理解,框架只是让我们更加方便、快捷的开发,框架里屏蔽了部分复杂却又不实用的东西,增加了部分常用东西。看一个web项目,首先就是查看web.xml中的定义。

<filter>  <filter-name>struts2</filter-name>  <filter-class>  org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter  </filter-class>  </filter>  <filter-mapping>  <filter-name>struts2</filter-name>  <url-pattern>/*</url-pattern>  </filter-mapping>

上面就是常见的struts的xml配置,而关键就是配置了一个Filter,过滤器。顾名思义,过滤器就是用于过滤请求的,它的功能,个人觉得可以近似为一个uri rewrite,当然,它还只属于一个代码的入口,不像WebServer的重写规则那么强大,但功能上是很近似的。

所以在Filter里,可能会做一些错误页重定向(例如50X,40X等页面的定向),当然也可以根据uri判断是哪个接口,调用并返回,这就是一般MVC框架单一入口的思想。

package demo.struts.filter;import javax.servlet.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.Date;public class MyFilter implements Filter{    public void destroy()    {        // TODO Auto-generated method stub    }    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException    {        //将ServletRequest变成HttpServletRequest        HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) res;        // TODO Auto-generated method stub        //        System.out.println("in Filter" + (new Date()).getTime());        //这里使用uri获取当前请求        System.out.println(RequestUtils.getUri(request));        //真正的struts通过namespace和actionName区分action的name和对应的类,通过method区分调用的方法        chain.doFilter(request, response);//这句是关键,表示接口放行,通过filterChain执行    }    public void init(FilterConfig filterConfig) throws ServletException    {        // TODO Auto-generated method stub        System.out.println("in init" + (new Date()).getTime());    }}
上面给出了一个最简单的Filter的写法,首先Filter需要复写接口Filter,并重写init、doFilter、destroy方法。init方法在项目启动时运行,destroy在项目结束时运行(可以认为是构造和析构),比较关键的是doFilter方法,该方法在所有http请求时都会运行。

不难想到,首先通过获取uri和struts.xml的配置获得ActionMap,如果map成功则执行ActionClass,否则就执行chain.doFilter(request, response);

当然,实际的struts也是这么实现的。

package org.apache.struts2.dispatcher.ng.filter;import org.apache.struts2.StrutsStatics;import org.apache.struts2.dispatcher.Dispatcher;import org.apache.struts2.dispatcher.mapper.ActionMapping;import org.apache.struts2.dispatcher.ng.ExecuteOperations;import org.apache.struts2.dispatcher.ng.InitOperations;import org.apache.struts2.dispatcher.ng.PrepareOperations;import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;/** * Executes the discovered request information.  This filter requires the {@link StrutsPrepareFilter} to have already * been executed in the current chain. */public class StrutsExecuteFilter implements StrutsStatics, Filter {    protected PrepareOperations prepare;    protected ExecuteOperations execute;    protected FilterConfig filterConfig;    public void init(FilterConfig filterConfig) throws ServletException {        this.filterConfig = filterConfig;    }    protected synchronized void lazyInit() {        if (execute == null) {            InitOperations init = new InitOperations();            Dispatcher dispatcher = init.findDispatcherOnThread();            init.initStaticContentLoader(new FilterHostConfig(filterConfig), dispatcher);            prepare = new PrepareOperations(filterConfig.getServletContext(), dispatcher);            execute = new ExecuteOperations(filterConfig.getServletContext(), dispatcher);        }    }    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {        HttpServletRequest request = (HttpServletRequest) req;        HttpServletResponse response = (HttpServletResponse) res;        if (excludeUrl(request)) {            chain.doFilter(request, response);            return;        }        // This is necessary since we need the dispatcher instance, which was created by the prepare filter        if (execute == null) {            lazyInit();        }        ActionMapping mapping = prepare.findActionMapping(request, response);        //if recusrion counter is > 1, it means we are in a "forward", in that case a mapping will still be        //in the request, if we handle it, it will lead to an infinte loop, see WW-3077        Integer recursionCounter = (Integer) request.getAttribute(PrepareOperations.CLEANUP_RECURSION_COUNTER);        if (mapping == null || recursionCounter > 1) {            boolean handled = execute.executeStaticResourceRequest(request, response);            if (!handled) {                chain.doFilter(request, response);            }        } else {            execute.executeAction(request, response, mapping);        }    }    private boolean excludeUrl(HttpServletRequest request) {        return request.getAttribute(StrutsPrepareFilter.REQUEST_EXCLUDED_FROM_ACTION_MAPPING) != null;    }    public void destroy() {        prepare = null;        execute = null;        filterConfig = null;    }}

当然在初始化时,struts使用了lazyinit模式,减轻在初始时的压力,节省资源。延迟加载的主要是两个对象,prepare和execute,两个都是工具性质的操作类,一个是用于获取ActionMapper的,一个用于执行Action的。

Filter作为struts的入口,是所有接口的一个过滤器,(当然也可以理解为一个拦截器,此处是为了过滤struts请求,交给struts处理)。过滤出请求之后,根据请求的uri定位到struts资源,唤起ActionSupport的execute方法。


0 0