zoukankan      html  css  js  c++  java
  • ActionContext实现原理

    StrutsPrepareAndExecuteFilter http://www.tuicool.com/articles/NVNbYn

    struts2  struts1 的一个重要区别就是它进行了 Action 类和 Servlet 的解耦。 

     

    又提供了获取 Servlet API 的其它通道,就是 ActionContext (还有个 ServletActionContext ,其实 ServletActionContext 只是 ActionContext 的一个子类而已)。源码为证:public class ServletActionContext extends ActionContext implements StrutsStatics

     

    ActionContext  Action 执行时的上下文,可以看作是一个容器,并且这个容器只是一个 Map

     

    ActionContext容器中存放的是 Action 在执行时需要用到的 VALUE_STACK  ACTION_NAME  SESSION  APPLICATION  ACTION_INVOCATION 等等对象,还可以存放自定义的一些对象。

     

    在一个请求的处理过程拦截器、 action 类和 result 中任何时候获取的 ActionContext 都是跟当前请求绑定那一个。

     

    首先是 ActionContext 类的源码:

    public class ActionContext implements Serializable{

      static ThreadLocal actionContext = new ThreadLocal();

      public static final String ACTION_NAME = "com.opensymphony.xwork2.ActionContext.name";

      public static final String VALUE_STACK = "com.opensymphony.xwork2.util.ValueStack.ValueStack";

      public static final String SESSION = "com.opensymphony.xwork2.ActionContext.session";

      public static final String APPLICATION = "com.opensymphony.xwork2.ActionContext.application";

      public static final String PARAMETERS = "com.opensymphony.xwork2.ActionContext.parameters";

      public static final String LOCALE = "com.opensymphony.xwork2.ActionContext.locale";

      public static final String TYPE_CONVERTER = "com.opensymphony.xwork2.ActionContext.typeConverter";

      public static final String ACTION_INVOCATION = "com.opensymphony.xwork2.ActionContext.actionInvocation";

      public static final String CONVERSION_ERRORS = "com.opensymphony.xwork2.ActionContext.conversionErrors";

      public static final String CONTAINER = "com.opensymphony.xwork2.ActionContext.container";

      Map<String, Object> context;

      public ActionContext(Map<String, Object> context)

      {

        this.context = context;

      }

      //... ...

      public static void setContext(ActionContext context)

      {

        actionContext.set(context);

      }

      public static ActionContext getContext()

      {

        return (ActionContext)actionContext.get();

      }

      public void setContextMap(Map<String, Object> contextMap)

      {

        getContext().context = contextMap;

      }

      public Map<String, Object> getContextMap()

      {

        return this.context;

      }

      //... ...

      public void setSession(Map<String, Object> session)

      {

        put("com.opensymphony.xwork2.ActionContext.session", session);

      }

      public Map<String, Object> getSession()

      {

        return (Map)get("com.opensymphony.xwork2.ActionContext.session");

      }

      //... ...

      public Object get(String key)

      {

        return this.context.get(key);

      }

      public void put(String key, Object value)

      {

        this.context.put(key, value);

      }

    }

    源码清晰的说明了我们编程中再熟悉不过的一行代码: ActionContext ctx = ActionContext.getContext();,原来我们所取得的ctx来自于 ThreadLocal 啊!熟悉 ThreadLocal 的朋友都知道它是与当前线程绑定的,而且是我们Java中处理多线程问题的一种重要方式。我们再看,类中有个 Map 类型的变量 context ,其实,它才是前面我们提到的真正意义上的容器,用来存放 Action 在执行时所需要的那些数据

     

    到这里,他最初的那个问题已经很了然了。但是,他紧接着又一个疑惑提出来了:那既然每个请求处理线程都有自己的 ActionContext ,那里面的那些数据是什么时候放进去的呢

     

    这次我给他的建议是,动脑筋,用源码验证。既然 ActionContext 存放有 HttpServletRequest 及其中的参数,既然 ActionContext 贯穿于整个请求处理过程,那就从struts2请求处理的入口(过滤器 StrutsPrepareAndExecuteFilter )找,源码:

     

    public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter

    {

      // ... ...

      public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)

        throws IOException, ServletException

      {

        HttpServletRequest request = (HttpServletRequest)req;

        HttpServletResponse response = (HttpServletResponse)res;

        try

        {

          this.prepare.setEncodingAndLocale(request, response);

          this.prepare.createActionContext(request, response);//就是在这里进行创建并初始化ActionContext实例

          this.prepare.assignDispatcherToThread();

          if ((this.excludedPatterns != null) && (this.prepare.isUrlExcluded(request, this.excludedPatterns))) {

            chain.doFilter(request, response);

          } else {

            request = this.prepare.wrapRequest(request);

            ActionMapping mapping = this.prepare.findActionMapping(request, response, true);

            if (mapping == null) {

              boolean handled = this.execute.executeStaticResourceRequest(request, response);

              if (!handled)

                chain.doFilter(request, response);

            }

            else {

              this.execute.executeAction(request, response, mapping);

            }

          }

        } finally {

          this.prepare.cleanupRequest(request);

        }

      }

       //... ...

    }

    再找到 prepare 对应的类 PrepareOperations ,查看方法 createActionContext () ,就一目了然了。

     

    对于 ServletActionContext 作为 ActionContext 一个直接子类,原理也是类似的,感兴趣的朋友可以看一下。

     

  • 相关阅读:
    现代软件工程 第一章 【概论】第8题——原旭莹,张晓丽
    现代软件工程 第一章 【概论】第2题——孙雪莹
    现代软件工程 第一章 【概论】第11题——原旭莹
    现代软件工程 第一章 【概论】第6题——原旭莹
    现代软件工程 第一章 【概论】第9题——孙雪莹
    现代软件工程 第一章 【概论】第7题——原旭莹
    现代软件工程 第一章 【概论】第12题——张晓丽
    现代软件工程 第一章 【概论】第5题——原旭莹
    现代软件工程 第一章 【概论】第4题——张功
    [Python]conda与 virtualenv虚拟环境配置
  • 原文地址:https://www.cnblogs.com/lsx1993/p/4841521.html
Copyright © 2011-2022 走看看