关于在Struts2中ActionContext是何时创建的

xiaoxiao2021-02-28  113

       首先我们要知道ActionContext是线程安全的,在每次执行Action之前都会创建新的ActionContext,也就是说在同一个线程里ActionContext里的属性是唯一的,这样我的Action就可以在多线程中使用。

       既然在每次执行Action之前都会创建新的ActionContext,那我们就从Struts2核心过滤器StrutsPrepareAndExecuteFilter来看起啊~

看源码:

public class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter { private static final Logger LOG = LogManager.getLogger(StrutsPrepareAndExecuteFilter.class); protected PrepareOperations prepare; protected ExecuteOperations execute; protected List<Pattern> excludedPatterns = null; public void init(FilterConfig filterConfig) throws ServletException { InitOperations init = createInitOperations(); Dispatcher dispatcher = null; try { FilterHostConfig config = new FilterHostConfig(filterConfig); init.initLogging(config); dispatcher = init.initDispatcher(config);//创建并初始化分派器 init.initStaticContentLoader(config, dispatcher); prepare = createPrepareOperations(dispatcher);//创建PrepareOperations对象 execute = createExecuteOperations(dispatcher); this.excludedPatterns = init.buildExcludedPatternsList(dispatcher); postInit(dispatcher, filterConfig); } finally { if (dispatcher != null) { dispatcher.cleanUpAfterInit(); } init.cleanup(); } } public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; try { String uri = RequestUtils.getUri(request); if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { LOG.trace("Request {} is excluded from handling by Struts, passing request to other filters", uri); chain.doFilter(request, response); } else { LOG.trace("Checking if {} is a static resource", uri); boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { LOG.trace("Assuming uri {} as a normal action", uri); prepare.setEncodingAndLocale(request, response); prepare.createActionContext(request, response);//就在这里啊,是由PrepareOperations.createActionContext()方法创建的, //具体在看PrepareOperations源码 prepare.assignDispatcherToThread(); request = prepare.wrapRequest(request); ActionMapping mapping = prepare.findActionMapping(request, response, true);//获取mapping if (mapping == null) { LOG.trace("Cannot find mapping for {}, passing to other filters", uri); chain.doFilter(request, response);//如果mapping为空,进入下一个过滤器,这就是FilterChain在这里要做的事。 } else { LOG.trace("Found mapping {} for {}", mapping, uri); execute.executeAction(request, response, mapping);//最后执行action } } } } finally { prepare.cleanupRequest(request); } } public void destroy() { prepare.cleanupDispatcher(); } }从源码可以看出,ActionContext是由PrepareOperations.createActionContext()方法创建的,再看PrepareOperations.createActionContext()。

贴源码:

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();//先获取oldContext if (oldContext != null) { // detected existing context, so we are probably in a forward ctx = new ActionContext(new HashMap<>(oldContext.getContextMap())); } else { ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();//这里创建了值栈 stack.getContext().putAll(dispatcher.createContextMap(request, response, null));//从这里看出,从dispatcher.createContextMap(request, response, null)获取一个map类型的context。 ctx = new ActionContext(stack.getContext());//再有这个context带入new 出一个新的ActionContext } request.setAttribute(CLEANUP_RECURSION_COUNTER, counter); ActionContext.setContext(ctx); return ctx; }从上面我们已经看出,真正new出ActionContext的地方是在PrepareOperations类中。那么这个时候的上下文中又有些什么呢?我们不妨再看下面dispatcher.createContextMap。

贴源码:有两个同名不同参数的createContextMap。

public Map<String,Object> createContextMap(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) { // request map wrapping the http request objects Map requestMap = new RequestMap(request); // parameters map wrapping the http parameters. ActionMapping parameters are now handled and applied separately HttpParameters params = HttpParameters.create(request.getParameterMap()).build(); // session map wrapping the http session Map session = new SessionMap(request); // application map wrapping the ServletContext Map application = new ApplicationMap(servletContext); Map<String,Object> extraContext = createContextMap(requestMap, params, session, application, request, response); if (mapping != null) { extraContext.put(ServletActionContext.ACTION_MAPPING, mapping); } return extraContext; } public HashMap<String,Object> createContextMap(Map requestMap, HttpParameters parameters, Map sessionMap, Map applicationMap, HttpServletRequest request, HttpServletResponse response) { HashMap<String, Object> extraContext = new HashMap<>(); extraContext.put(ActionContext.PARAMETERS, parameters); extraContext.put(ActionContext.SESSION, sessionMap); extraContext.put(ActionContext.APPLICATION, applicationMap); Locale locale; if (defaultLocale != null) { locale = LocalizedTextUtil.localeFromString(defaultLocale, request.getLocale()); } else { locale = request.getLocale(); } extraContext.put(ActionContext.LOCALE, locale); extraContext.put(StrutsStatics.HTTP_REQUEST, request); extraContext.put(StrutsStatics.HTTP_RESPONSE, response); extraContext.put(StrutsStatics.SERVLET_CONTEXT, servletContext); // helpers to get access to request/session/application scope extraContext.put("request", requestMap); extraContext.put("session", sessionMap); extraContext.put("application", applicationMap); extraContext.put("parameters", parameters); AttributeMap attrMap = new AttributeMap(extraContext); extraContext.put("attr", attrMap); return extraContext; }上面的源码不难,我们常用的request、session、application、parameters等都在这里啊~~~ 好了,就到这了。我也是边学边总结,要是哪里有问题,各位帮忙指出。

创建好ActionContext后获取mapping,最后执行action,都在doFilter里面,大家可以一步一步再研究下源码、

转载请注明原文地址: https://www.6miu.com/read-34159.html

最新回复(0)