首页 > 代码库 > Struts Actioncontext 和ServletConfigInterceptor的原理分析

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和内置对象。

 

Struts Actioncontext 和ServletConfigInterceptor的原理分析