上图提供了struts2的执行流程。如下:
1:从客户端发出请求(HTTPServletRequest)。
2:请求经过各种过滤器(filter),注:一般情况下,如SiteMesh等其他过滤器要放在核心控制器FilterDispatcher之前,也就是web.xml中配置的filter-mapping在
StrutsPrepareAndExecuteFilter之前. 在执行完了所有的过滤器的doFilter方法之后,核心控制器FilterDispatcher会清空ActionContext。所以, 其中ActionContextCleanUp作用是在doFilter里设置了一个计数器,使后续的filter不会清空ActionContext,最后执行完流程后由ActionContextCleanUp清空。如果没有ActionContextCleanUp,如果涉及到struts2中的如valuestack中的数据时会有可能得不到想要的数据。
3:经过各种过滤器后,到达核心控制器FilterDispatcher,被调用后,通过struts.xml配置文件中Action标签中的映射来确定调用的Action方法,
4:当确定了调用的Action之后会找到反射生成的指定Action的代理对象(ActionProxy),
5:ActionProxy会通过配置文件信息找到指定的Action,
6:然后会经过系统和自定义拦截器栈,拦截器中都有重写一个public String doIntercept(ActionInvocation invocation) throws Exception{}的方法,
拦截器中会通过判断有执行invocation.invoke()返回一个字符串,来连接到下一个拦截器或者到达执行Action。
7:action执行完毕后,会返回一个字符串,该字符串与配置文件Action中result的name属性相对应,将处理得到的数据封装到此视图来,
8:在依次出了拦截器栈之后,将数据响应(HttpServletResponse)到客户端。其中在经过ActionContextCleanUp时候会清空ActionContext。
由上面执行流程可以看出Action与servlet不同:
Servlet是单实例多线程的,而Action是多实例多线程的。因为多实例,所有每个请求会产生不同的Action和ActionContext对象,因此线程是安全的。同时因为Action是多实例的,所以Action中可以有成员变量,因为多实例不会公用。
而Servlet是单实例多线程,所以一般情况下不会定义成员变量,因为共用同一个成员变量可能出现线程安全的问题。
Servlet的单例不由class来决定,而是由您在web.xml里配置的servlet-name来决定。也就是说每一个servlet-name只有1个单例
一定要注意servlet的线程安全问题,因为servlet是单例的,如果你在servlet里面定义成员变量,就会被多个请求的线程锁访问,导致线程安全问题,所以一定要注意servlet的线程安全问题,action是每一次请求都会产生一个action,所以是不会存在线程安全问题的
所以在清单文件里面配置的时候action 的scope配置为prototype表示每次请求都产生一个action