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存入ActionContext和值栈中。

如果实现了***Aware接口,就会从ActionContext中获取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和内置对象。

 

转载于:https://www.cnblogs.com/rcboy/p/5876927.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值