`
esperanza
  • 浏览: 183351 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

struts2 StrutsPrepareAndExecuteFilter 源码分析

阅读更多

概述

         近期在看struts2,在看到论坛上有人分析了StrutsPrepareAndExecuteFilter的源码,感觉这个类是很核心的,可以知道struts2拦截到用户请求之后是如何对参数进行转换的。我就按图索骥,也来走读一下这个类的代码,大家多指教。

在使用struts的时候要在web.xml中配置一个过滤器,来拦截用户发起的请求,并进行一些预处理,根据配置文件把请求分配给对应的action并将请求中的参数与action中的字段进行对应赋值。现在就来解读一下,这背后都发生了哪些事情。

在一些介绍struts2的博客中,使用的过滤器是FilterDispatcher,在文档中我们可以看到如下的说明:

Deprecated.Since Struts 2.1.3, use StrutsPrepareAndExecuteFilter instead or StrutsPrepareFilter and StrutsExecuteFilter if needing using the ActionContextCleanUp filter in addition to this one

StrutsPrepareAndExecuteFilter的说明如下:

Handles both the preparation and execution phases of the Struts dispatching process. This filter is better to use when you don't have another filter that needs access to action context information, such as Sitemesh.

2个说明就不做过多的说明了。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>

过滤器

要构建一个过滤器很简单就是实现javax.servlet.Filter接口即可。这个接口有三个方法:

Ø  init() :这个方法在容器实例化过滤器时被调用,它主要设计用于使过滤器为处理做准备。该方法接受一个 FilterConfig 类型的对象作为输入。

Ø  doFilter() :与 servlet 拥有一个 service() 方法(这个方法又调用 doPost() 或者 doGet() )来处理请求一样,过滤器拥有单个用于处理请求和响应的方法doFilter() 。这个方法接受三个输入参数:一个 ServletRequest response 和一个 FilterChain 对象。

Ø  destroy() :正如您想像的那样,这个方法执行任何清理操作,这些操作可能需要在自动垃圾收集之前进行。

源码剖析

  正如文档中的描述,use StrutsPrepareAndExecuteFilter instead or StrutsPrepareFilter and StrutsExecuteFilter,在StrutsPrepareAndExecuteFilter类中有2个字段,分别声明了StrutsPrepareFilterStrutsExecuteFilter的实例。现在先来看看init方法

init方法

    public void init(FilterConfig filterConfig) throws ServletException {

    //一个集中了多个初始化方法的工具类

        InitOperations init = new InitOperations();

        try {

        //包装javax.servlet.FilterConfig对象

//重新实现了getInitParameterNames()方法

//把返回值由Enumeration类型转化为Iterator类型

            FilterHostConfig config = new FilterHostConfig(filterConfig);

            //初始化日志

            init.initLogging(config);

            //创建Dispatcher 包含了2方面的信息:servletcontext,拦截器的配置参数

            //同时指定了初始化配置文件的顺序

            Dispatcher dispatcher = init.initDispatcher(config);

            init.initStaticContentLoader(config, dispatcher);

            //PrepareOperations为请求处理做一些准备工作

            prepare =

new PrepareOperations(filterConfig.getServletContext(), dispatcher);

            execute =

new ExecuteOperations(filterConfig.getServletContext(), dispatcher);

//哪些请求是被过滤掉的, 不执行拦截器

          this.excludedPatterns = init.buildExcludedPatternsList(dispatcher);

            //回调方法

            postInit(dispatcher, filterConfig);

        } finally {

            init.cleanup();

        }

}

新建dispatcher的代码如下:

    private Dispatcher createDispatcher( HostConfig filterConfig ) {

        Map<String, String> params = new HashMap<String, String>();

        for ( Iterator e = filterConfig.getInitParameterNames(); e.hasNext();){

            String name = (String) e.next();

            String value = filterConfig.getInitParameter(name);

            params.put(name, value);

        }

        return new Dispatcher(filterConfig.getServletContext(), params);

}

private void init_DefaultProperties() {

        configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());

    }

doFilter

     doFilter是过滤器的执行方法,它拦截提交的HttpServletRequest请求,HttpServletResponse响应,是strtus2的核心拦截器。简单的分析如下:

public void doFilter(ServletRequest req, ServletResponse res,

FilterChain chain) throws IOException, ServletException {

    HttpServletRequest request = (HttpServletRequest) req;

HttpServletResponse response = (HttpServletResponse) res;

    try {

      //设置字符编码集

      prepare.setEncodingAndLocale(request, response);

      //创建actioncontext

      prepare.createActionContext(request, response);

      //Dispater有一个静态的Threadlocal变量,为每个线程保存一个副本

      prepare.assignDispatcherToThread();

     if ( excludedPatterns != null &&

prepare.isUrlExcluded(request, excludedPatterns)) {

         chain.doFilter(request, response);

    } else {

        //如果是文件上传请求会封装称:MultiPartRequestWrapper

//否则为:StrutsRequestWrapper

        //封装之后可以访问actioncontext,并使用OGNL表达式了

        request = prepare.wrapRequest(request);

        //No mapping will be created in the case of static resource requests

        //or unidentifiable requests for other servlets

        ActionMapping mapping = prepare.findActionMapping(

request, response, true);

        if (mapping == null) {

            //Tries to execute a request for a static resource

            //对这个没有一个太感性的认识

            boolean handled =

execute.executeStaticResourceRequest(request, response);

            if (!handled) {

                chain.doFilter(request, response);

            }

        } else {

            //处理请求,读取配置文件,利用反射机制生成一个action代理

            execute.executeAction(request, response, mapping);

        }

    }

  } finally {

      prepare.cleanupRequest(request);

  }

}

为请求新建一个actioncontext的代码如下:

public ActionContext createActionContext(

HttpServletRequest request, HttpServletResponse response) {

   ActionContext ctx;

   Integer counter = 1;

   //暂时不知道这个计数器有啥用

  Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);

  if (oldCounter != null) {

      counter = oldCounter + 1;

  }

  ActionContext oldContext = ActionContext.getContext();

  if (oldContext != null) {

      // detected existing context, so we are probably in a forward

      ctx = new ActionContext(

new HashMap<String, Object>(oldContext.getContextMap()));

  } else {

      ValueStack stack = dispatcher.getContainer().getInstance

(ValueStackFactory.class).createValueStack();

      //stack.getContext()就是个Map<String, Object>

      //dispatcher.createContextMap()封装了http请求相关的信息

      //比如:requestreponseServletContexthttp parameterssession,application

      //感觉所谓的context其实就可以认为是一个集合类,保存了http请求的相关信息

      stack.getContext().putAll(dispatcher.createContextMap(

request, response, null, servletContext));

//通过这里我们看出来,actioncontext包含了哪些东西:

//request,reposne,session,application中的参数以及valuestack

     //通过OGNL获取数据的方式可以得到对应

     ctx = new ActionContext(stack.getContext());

  }

 

  request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);

  ActionContext.setContext(ctx);

  return ctx;

}

另外一篇不错的帖子

http://www.iteye.com/topic/829843

 

分享到:
评论
2 楼 yangxiutian 2012-10-19  
想查查新版的struts2的工作原理   网上全是旧版的
1 楼 nurenok 2012-04-25  
  postInit(dispatcher, filterConfig);
这个究竟有啥用

相关推荐

    struts2源码分析总结

    本文将深入探讨Struts2的源码分析,特别是关于StrutsPrepareAndExecuteFilter的初始化过程,这是Struts2的核心组件之一,负责处理HTTP请求。 首先,我们来看`StrutsPrepareAndExecuteFilter`的初始化。这个过滤器...

    struts2框架源码分析及问题汇总

    3. StrutsPrepareAndExecuteFilter:这是Struts2的过滤器,用于初始化和处理请求。它在web.xml中配置,负责拦截请求并将其交给Struts2的Dispatcher。 4. ActionMapper:ActionMapper根据请求URL映射到相应的Action...

    struts2的源码

    10. **S2运行时架构**:学习源码还能帮助理解Struts2的整体架构,如FilterDispatcher(或现在的StrutsPrepareAndExecuteFilter)如何作为Servlet Filter工作,以及RequestProcessor的角色。 通过深入研究Struts2的...

    Struts2源码

    源码分析对于开发者来说是深入理解框架工作原理、优化代码以及解决技术问题的关键。Struts2的核心在于提供一个灵活的请求处理机制,以及强大的动作调度和结果渲染。 首先,我们来看看Struts2的架构设计。Struts2...

    struts 2 源码 导入eclipse工程

    7. **Plug-in体系结构**:Struts 2支持插件化开发,通过StrutsPrepareAndExecuteFilter和相应的插件,可以轻松地扩展框架功能。 8. **生命周期与工作流程**:当一个HTTP请求到达时,Struts 2会通过...

    struts2案例 struts2 struts2源码

    下面,我们将深入探讨Struts2的核心概念、源码分析以及如何利用它来创建实际的案例。 首先,Struts2的架构基于Action和Result的设计模式,Action是业务逻辑的载体,Result则是处理Action执行后展示结果的方式。这种...

    struts2-core-2.0.11源码

    在源码分析中,以下几个关键知识点是非常重要的: 1. **拦截器(Interceptors)**:Struts2的核心特性之一,拦截器负责在Action调用前后执行额外的逻辑,如日志记录、权限验证等。在`org.apache.struts2....

    StrutsPrepareAndExecuteFilter源码剖析

    析&lt;/STRONG&gt; 9....通过分析其源码,我们可以深入了解 Struts2 的工作原理,包括请求处理流程、拦截器机制、配置加载等关键环节。这对于开发者来说,无论是排查问题还是优化性能,都有着重要的指导意义。

    struts 1 源码分析

    以上是对Struts 1.2源码分析的关键点,通过深入理解这些概念和机制,开发者可以更好地优化和维护基于Struts 1的应用程序,同时为学习其他MVC框架,如Spring MVC或Struts 2,打下坚实基础。然而,由于Struts 1的安全...

    xwork_struts2 源码

    3. **源码分析**:研究这两个jar的源码,可以深入理解Struts2的工作原理,包括: - **ActionInvocation**:它是Action执行过程的封装,负责调用Interceptor链并执行Action方法。 - **...

    struts2-core-2.3.7源码

    Struts2是一个基于MVC(Model-View-...总之,`struts2-core-2.3.7`源码的分析将带你走进Struts2框架的深处,帮助你成为一名更熟练的Java Web开发者,理解Web应用的复杂性,以及如何优雅地处理用户请求和业务逻辑。

    浪曦struts2源码第5课

    6. **生命周期与请求处理**:当一个HTTP请求到达时,Struts2如何从DispatcherServlet开始,通过FilterDispatcher或StrutsPrepareAndExecuteFilter来处理请求,然后如何找到对应的Action并执行,这些都是源码分析的...

    struts2参考资料

    在Struts2的源码分析中,我们可以深入理解其工作原理。首先,入口点是`FilterDispatcher`或`StrutsPrepareAndExecuteFilter`,这两个过滤器负责拦截HTTP请求并将其导向Struts2的处理流程。接着,`ActionContext`保存...

    浪曦struts2源码15课

    通过深入学习"浪曦struts2源码15课",你可以掌握Struts2框架的核心组件,如Action、Result、Interceptor(拦截器)的运作方式,理解Struts2的配置机制,以及如何使用Struts2进行MVC架构的开发。此外,还能了解如何...

    struts2源码研究

    Struts2 源码分析主要涉及其在Tomcat启动过程中的初始化步骤以及请求处理流程。首先,我们来看Tomcat启动时Struts2框架如何准备和执行。 在Tomcat启动时,Struts2的Filter文件被加载,具体是`...

    struts2 源码

    源码分析是深入理解框架运作机制的关键,以下将详细探讨Struts2的核心概念、架构和关键组件。 1. **核心概念** - **Action**:在Struts2中,Action是业务逻辑处理的主要类,负责接收请求并执行相应的操作。 - **...

    浪曦struts2源码第四课

    源码分析方面,我们可以从以下几个关键点入手: 1. **ActionInvocation**:它是执行Action的核心接口,包含了调用Action方法和执行拦截器链的逻辑。 2. **DefaultActionProxy**:负责创建ActionInvocation实例,并...

    Struts2 HelloWorld

    我们需要在项目的web.xml文件中配置Struts2的核心过滤器`org.apache.struts2.dispatcher.FilterDispatcher`或更现代的`org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter`。这个过滤器负责...

    struts2 拦截器

    ### 六、Struts2 源码分析 深入研究Struts2的源码有助于我们更好地理解拦截器的工作原理。例如,`DefaultActionInvocation`类是Action调用的核心,它负责调度拦截器和Action的执行;`InterceptorStack`则管理拦截器...

    struts2源代码

    - Struts2的入口点是`org.apache.struts2.dispatcher.FilterDispatcher`(在新版本中更改为`StrutsPrepareAndExecuteFilter`),它是一个Servlet Filter,负责拦截HTTP请求并转发给Struts2处理。 7. **国际化与...

Global site tag (gtag.js) - Google Analytics