①,Struts1通过缓存来管理action对象,并且使用了单例模式,就是一个action只产生一个实例对象,这个实例对象要处理所有对应的request,所以Action类里面不应该有可变的全局变量,我们应该把所有的变量都封装到ActionForm里面。
来看下Struts1的生成action实例对象的源代码:
1 protected Action processActionCreate(HttpServletRequest request, 2 HttpServletResponse response, ActionMapping mapping) 3 throws IOException { 4 // 获取action类的名字 5 String className = mapping.getType(); 6 7 if (log.isDebugEnabled()) { 8 log.debug(" Looking for Action instance for class " + className); 9 } 10 11 Action instance; 12 13 // 加锁处理。 14 synchronized (actions) { 15 // 如果此Action已经被创建过对象了,则直接返回已经创建好的对象。 16 instance = (Action) actions.get(className); 17 18 if (instance != null) { 19 if (log.isTraceEnabled()) { 20 log.trace(" Returning existing Action instance"); 21 } 22 23 return (instance); 24 } 25 26 // 如果还没有被创建对象,则创建一个再返回。 27 if (log.isTraceEnabled()) { 28 log.trace(" Creating new Action instance"); 29 } 30 31 try { 32 instance = (Action) RequestUtils.applicationInstance(className); 33 34 // Maybe we should propagate this exception 35 // instead of returning null. 36 } catch (Exception e) { 37 log.error(getInternal().getMessage("actionCreate", 38 mapping.getPath()), e); 39 40 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, 41 getInternal().getMessage("actionCreate", mapping.getPath())); 42 43 return (null); 44 } 45 46 // 把新创建好的对象放到缓存中。 47 actions.put(className, instance); 48 49 if (instance.getServlet() == null) { 50 instance.setServlet(this.servlet); 51 } 52 } 53 54 return (instance); 55 }
从代码中我们可以看出,struts1使用了一个actions的缓存来管理所有的action实例对象,当请求一个action对象时,先到actions里面查找对应的action对象,如果存在,则直接返回此对象,如果不存在,则新创建一个action对象,然后加到缓存中,再返回新创建的action实例对象。
②,struts2和struts1不同,struts2会为每个请求都创建一个action对象实例,所以不存在线程安全的问题。
还是看源码:
StrutsPrepareAndExecuteFilter类的doFilter方法:
1 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 2 3 HttpServletRequest request = (HttpServletRequest) req; 4 HttpServletResponse response = (HttpServletResponse) res; 5 6 try { 7 prepare.setEncodingAndLocale(request, response); 8 prepare.createActionContext(request, response); 9 // 把dispatcher绑定到当前线程上,作为当前线程的局部变量。 10 prepare.assignDispatcherToThread(); 11 if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { 12 chain.doFilter(request, response); 13 } else { 14 request = prepare.wrapRequest(request); 15 ActionMapping mapping = prepare.findActionMapping(request, response, true); 16 if (mapping == null) { 17 boolean handled = execute.executeStaticResourceRequest(request, response); 18 if (!handled) { 19 chain.doFilter(request, response); 20 } 21 } else { 22 execute.executeAction(request, response, mapping); 23 } 24 } 25 } finally { 26 // 此处清楚线程局部变量。 27 prepare.cleanupRequest(request); 28 } 29 }
从上面的代码中可以看出,struts2把dispatcher作为局部变量绑定到了线程上,而Dispatcher是struts2的核心分发器,所有的action初始化操作都是在它控制之下,所以struts2是线程安全的。