Struts Actioncontext 和ServletConfigInterceptor的原理分析

最近你在做网上商城的项目时对Struts的Actioncontext的原理产生的疑问,于是通过查找资料最后有了一定理解,在此写下随笔为自己的思路做整理。

web.xml代码:

1 <filter>
2         <filter-name>struts2</filter-name>
3         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
4     </filter>
5     <filter-mapping>
6         <filter-name>struts2</filter-name>
7         <url-pattern>/*</url-pattern>
8     </filter-mapping>

在web.xml配置文件中我们都有配置StrutsPrepareAndExecuteFilter这就意味着StrutsPrepareAndExecuteFilter拦截器在tomcat启动之时就比加载,并且拦截所有的action请求。

StrutsPrepareAndExecuteFilter中的doFilter如下:

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;

        try {
            if(this.excludedPatterns != null && this.prepare.isUrlExcluded(request, this.excludedPatterns)) {
                chain.doFilter(request, response);
            } else {
                this.prepare.setEncodingAndLocale(request, response);
                this.prepare.createActionContext(request, response);
                this.prepare.assignDispatcherToThread();
                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);
        }

    }

在StrutsPrepareAndExecuteFilter的dofilter方法中我们可以看到一个一行  this.prepare.createActionContext(request, response);  这样的代码其中传入了  HttpServletRequest和HttpServletResponse。我们继续往createActionContext  方法看。

PrepareOperations类中createActionContext方法代码:

public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        Integer counter = Integer.valueOf(1);
        Integer oldCounter = (Integer)request.getAttribute("__cleanup_recursion_counter");
        if(oldCounter != null) {
            counter = Integer.valueOf(oldCounter.intValue() + 1);
        }

        ActionContext oldContext = ActionContext.getContext();
        ActionContext ctx;
        if(oldContext != null) {
            ctx = new ActionContext(new HashMap(oldContext.getContextMap()));
        } else {//          创建值栈
            ValueStack stack = ((ValueStackFactory)this.dispatcher.getContainer().getInstance(ValueStackFactory.class)).createValueStack();//          把后面所获取到的map赋值到值栈的Map中
            stack.getContext().putAll(this.dispatcher.createContextMap(request, response, (ActionMapping)null));//           把值栈的map存储到ActionContext中一份
            ctx = new ActionContext(stack.getContext());
        }

        request.setAttribute("__cleanup_recursion_counter", counter);
        ActionContext.setContext(ctx);
        return ctx;
    }

在上面的方法中首先判断是否有ActionContext   如果没有的话就创建一个,如果有的话就创建一个值栈并且把后面所获取到的map赋值到值栈的Map中。最后又把值栈的map存储到ActionContext中一份

进一步分析creatContextMap方法:

 public Map<String, Object> createContextMap(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) {//      封装内置request对象
        RequestMap requestMap = new RequestMap(request);//      封装内置的request对象的参数
        HashMap params = new HashMap(request.getParameterMap());
        SessionMap session = new SessionMap(request);
        ApplicationMap application = new ApplicationMap(this.servletContext);
        HashMap extraContext = this.createContextMap(requestMap, params, session, application, request, response);
        if(mapping != null) {
            extraContext.put("struts.actionMapping", mapping);
        }

        return extraContext;
    }

在这个方法中封装了传入的各个内置对象并把各个内置对象和map传给了createContextMap方法

public HashMap<String, Object> createContextMap(Map requestMap, Map parameterMap, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response) {
       //  存储了所有的map和内置对象,最后次map被返回        HashMap extraContext = new HashMap();
        extraContext.put("com.opensymphony.xwork2.ActionContext.parameters", new HashMap(parameterMap));
        extraContext.put("com.opensymphony.xwork2.ActionContext.session", sessionMap);
        extraContext.put("com.opensymphony.xwork2.ActionContext.application", applicationMap);
        Locale locale;
        if(this.defaultLocale != null) {
            locale = LocalizedTextUtil.localeFromString(this.defaultLocale, request.getLocale());
        } else {
            locale = request.getLocale();
        }

        extraContext.put("com.opensymphony.xwork2.ActionContext.locale", locale);
        extraContext.put("com.opensymphony.xwork2.dispatcher.HttpServletRequest", request);
        extraContext.put("com.opensymphony.xwork2.dispatcher.HttpServletResponse", response);
        extraContext.put("com.opensymphony.xwork2.dispatcher.ServletContext", this.servletContext);
        extraContext.put("request", requestMap);
        extraContext.put("session", sessionMap);
        extraContext.put("application", applicationMap);
        extraContext.put("parameters", parameterMap);
        AttributeMap attrMap = new AttributeMap(extraContext);
        extraContext.put("attr", attrMap);//      返回给ActionConetext和值栈。
        return extraContext;
    }

综上:

在项目启动时的时候Struts的过滤器把相应的内置对象和内置对象的相应的map存入ActionContest和值栈中。

如果实现了***Aware接口,就会从ActionContest中获取map并传入,该功能主要有servletConfig拦截器实现:

  public String intercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();
        ActionContext context = invocation.getInvocationContext();
        HttpServletRequest servletContext;
        if(action instanceof ServletRequestAware) {
            servletContext = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
            ((ServletRequestAware)action).setServletRequest(servletContext);
        }

        if(action instanceof ServletResponseAware) {
            HttpServletResponse servletContext1 = (HttpServletResponse)context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");
            ((ServletResponseAware)action).setServletResponse(servletContext1);
        }

        if(action instanceof ParameterAware) {
            ((ParameterAware)action).setParameters(context.getParameters());
        }

        if(action instanceof ApplicationAware) {
            ((ApplicationAware)action).setApplication(context.getApplication());
        }

        if(action instanceof SessionAware) {
            ((SessionAware)action).setSession(context.getSession());
        }

        if(action instanceof RequestAware) {
            ((RequestAware)action).setRequest((Map)context.get("request"));
        }

        if(action instanceof PrincipalAware) {
            servletContext = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
            if(servletContext != null) {
                ((PrincipalAware)action).setPrincipalProxy(new ServletPrincipalProxy(servletContext));
            }
        }

        if(action instanceof ServletContextAware) {
            ServletContext servletContext2 = (ServletContext)context.get("com.opensymphony.xwork2.dispatcher.ServletContext");
            ((ServletContextAware)action).setServletContext(servletContext2);
        }

        return invocation.invoke();
    }

通过判断是否实现相应的接口来获取相应的map和内置对象。

时间: 2024-12-21 13:34:31

Struts Actioncontext 和ServletConfigInterceptor的原理分析的相关文章

SpringMvc框架MockMvc单元测试注解及其原理分析

来源:https://www.yoodb.com/ 首先简单介绍一下Spring,它是一个轻量级开源框架,简单的来说,Spring是一个分层的JavaSE/EEfull-stack(一站式) 轻量级开源框架.特点方便解耦,简化开发,AOP编程的支持声明式,事务的支持以及降低Java EE API的使用难度等. 目前主流的Web MVC框架除了Struts之外就是SpringMVC,不过要想灵活运用SpringMVC来应对大多说的web开发除了必须掌握其配置和原理外还需要会测试.在Spring3.

kafka producer实例及原理分析

1.前言 首先,描述下应用场景: 假设,公司有一款游戏,需要做行为统计分析,数据的源头来自日志,由于用户行为非常多,导致日志量非常大.将日志数据插入数据库然后再进行分析,已经满足不了.最好的办法是存日志,然后通过对日志的分析,计算出有用的数据.我们采用kafka这种分布式日志系统来实现这一过程. 步骤如下: 搭建KAFKA系统运行环境 如果你还没有搭建起来,可以参考我的博客: http://zhangfengzhe.blog.51cto.com/8855103/1556650 设计数据存储格式

android脱壳之DexExtractor原理分析[zhuan]

http://www.cnblogs.com/jiaoxiake/p/6818786.html内容如下 导语: 上一篇我们分析android脱壳使用对dvmDexFileOpenPartial下断点的原理,使用这种方法脱壳的有2个缺点: 1.  需要动态调试 2.  对抗反调试方案 为了提高工作效率, 我们不希望把宝贵的时间浪费去和加固的安全工程师去做对抗.作为一个高效率的逆向分析师, 笔者是忍不了的,所以我今天给大家带来一种的新的脱壳方法——DexExtractor脱壳法. 资源地址: Dex

android脱壳之DexExtractor原理分析

导语: 上一篇我们分析android脱壳使用对dvmDexFileOpenPartial下断点的原理,使用这种方法脱壳的有2个缺点: 1.  需要动态调试 2.  对抗反调试方案 为了提高工作效率, 我们不希望把宝贵的时间浪费去和加固的安全工程师去做对抗.作为一个高效率的逆向分析师, 笔者是忍不了的,所以我今天给大家带来一种的新的脱壳方法--DexExtractor脱壳法. 资源地址: DexExtractor源码:https://github.com/bunnyblue/DexExtracto

Adaboost算法原理分析和实例+代码(简明易懂)

Adaboost算法原理分析和实例+代码(简明易懂) [尊重原创,转载请注明出处] http://blog.csdn.net/guyuealian/article/details/70995333     本人最初了解AdaBoost算法着实是花了几天时间,才明白他的基本原理.也许是自己能力有限吧,很多资料也是看得懵懵懂懂.网上找了一下关于Adaboost算法原理分析,大都是你复制我,我摘抄你,反正我也搞不清谁是原创.有些资料给出的Adaboost实例,要么是没有代码,要么省略很多步骤,让初学者

Android视图SurfaceView的实现原理分析

附:Android控件TextView的实现原理分析 来源:http://blog.csdn.net/luoshengyang/article/details/8661317 在Android系统中,有一种特殊的视图,称为SurfaceView,它拥有独立的绘图表面,即它不与其宿主窗口共享同一个绘图表面.由于拥有独立的绘图表面,因此SurfaceView的UI就可以在一个独立的线程中进行绘制.又由于不会占用主线程资源,SurfaceView一方面可以实现复杂而高效的UI,另一方面又不会导致用户输

AbstractQueuedSynchronizer的介绍和原理分析(转)

简介 提供了一个基于FIFO队列,可以用于构建锁或者其他相关同步装置的基础框架.该同步器(以下简称同步器)利用了一个int来表示状态,期望它能够成为实现大部分同步需求的基础.使用的方法是继承,子类通过继承同步器并需要实现它的方法来管理其状态,管理的方式就是通过类似acquire和release的方式来操纵状态.然而多线程环境中对状态的操纵必须确保原子性,因此子类对于状态的把握,需要使用这个同步器提供的以下三个方法对状态进行操作: java.util.concurrent.locks.Abstra

linux中mmap系统调用原理分析与实现

参考文章:http://blog.csdn.net/shaoguangleo/article/details/5822110 linux中mmap系统调用原理分析与实现 1.mmap系统调用(功能)      void* mmap ( void * addr , size_t len , int prot , int flags ,int fd , off_t offset )      内存映射函数mmap, 负责把文件内容映射到进程的虚拟内存空间, 通过对这段内存的读取和修改,来实现对文件的

Android 4.4 KitKat NotificationManagerService使用详解与原理分析(一)__使用详解

概况 Android在4.3的版本中(即API 18)加入了NotificationListenerService,根据SDK的描述(AndroidDeveloper)可以知道,当系统收到新的通知或者通知被删除时,会触发NotificationListenerService的回调方法.同时在Android 4.4 中新增了Notification.extras 字段,也就是说可以使用NotificationListenerService获取系统通知具体信息,这在以前是需要用反射来实现的. 转载请