spring源码分析-controller的线程安全

大家都知道,struts1.2由于是线程安全的,每一个请求都去实例化一个action,造成大量并发时的资源浪费。 

  struts2在这一点上做了改进,每个action都是一个singleton,所有的请求都是请求同一个action实例。这样在一定程度上能节约资源,但又有安全问题。最常见的就是在action中声明有块状的实例变量,因为这一点是不被提倡的。如果一定要声明,那一定要加上同步块。 

  那么在spring mvc中的controller是不是线程安全的呢?答案是否定的。controller在默认情况下也是非线程安全的,我们来看看源码: 

Java代码  

  1.  * @author John A. Lewis  
  2.  * @author Juergen Hoeller  
  3.  * @since 2.0  
  4.  * @see ResourceAwareController  
  5.  * @see EventAwareController  
  6.  */  
  7. public abstract class AbstractController extends PortletContentGenerator implements Controller {  
  8.   
  9.     [color=red]private boolean synchronizeOnSession = false;[/color]  

由上面源码可知,controller默认是非安全的。 

Java代码  

  1.       
  2. public void handleActionRequest(ActionRequest request, ActionResponse response) throws Exception {  
  3.         // Delegate to PortletContentGenerator for checking and preparing.  
  4.         check(request, response);  
  5.   
  6.         // Execute in synchronized block if required.  
  7.                 //只有synchronizeOnSession设置为true,才会同步处理请求  
  8.         if (this.synchronizeOnSession) {  
  9.             PortletSession session = request.getPortletSession(false);  
  10.             if (session != null) {  
  11.                 synchronized (session) {  
  12.                     handleActionRequestInternal(request, response);  
  13.                     return;  
  14.                 }  
  15.             }  
  16.         }  
  17.   
  18.         handleActionRequestInternal(request, response);  
  19.     }  

只有手工设置controller的synchronizeOnSession值为true,才会被同步处理。 

因此,我们在使用spring mvc 的contrller时,应避免在controller中定义实例变量。 

##### 更正 ####################################
 

由于在下对struts1.x的理解也来自网络,给大家带来不便,还请见谅。 

经过对struts1.x源码的研读发现: 

struts1.2获取action的方式是单例的,所有的action都被维护在一个hashMap里,当有请求到达时,先根据action的名称去hashMap里查找要请求的Action是否已经存在,如果存在,则直接返回hashMap里的action。如果不存在,则创建一个新的Action实例。
 

下面我们来分析一下源码: 

请求到达ActionServlet时,首先会到达doGet()或doPost()方法,而ActionServlet转给了process()方法进行统一处理 

Java代码  

  1. public void doPost(HttpServletRequest request,  
  2.            HttpServletResponse response)  
  3.     throws IOException, ServletException {  
  4.   
  5.     process(request, response);  
  6.   
  7. }  

而process()方法又会转给processor的process()方法进行处理 

Java代码  

  1. protected void process(HttpServletRequest request, HttpServletResponse response)  
  2.     throws IOException, ServletException {  
  3.   
  4.     …  
  5.     processor.process(request, response);  
  6.   
  7. }  

processor的process()方法里经过一系列处理后,最后通过processActionCreate方法来返回一个具体的action实例

Java代码  

  1. public void process(HttpServletRequest request,  
  2.                         HttpServletResponse response)  
  3.         throws IOException, ServletException {  
  4.   
  5.         …  
  6.   
  7.         // Create or acquire the Action instance to process this request  
  8.         Action action = processActionCreate(request, response, mapping);  
  9.         if (action == null) {  
  10.             return;  
  11.         }  
  12.   
  13.      …  
  14.   
  15.     }  

那我们就到processActionCreate这个方法里去一窥究竟吧: 

1、先获取类名 

2、根据类名去map里查寻实例是否已经存在 

3、如果存在,则直接返回 

4、如果不存在,则创建一个新实例 

5、把创建好的action放到map里备用 

Java代码  

  1.     
  2. protected Action processActionCreate(HttpServletRequest request,  
  3.                                          HttpServletResponse response,  
  4.                                          ActionMapping mapping)  
  5.         throws IOException {  
  6.   
  7.         // Acquire the Action instance we will be using (if there is one)  
  8.         String className = mapping.getType();//1、先获取类名   
  9.         …  
  10.         Action instance = null;  
  11.         synchronized (actions) {  
  12.   
  13.             // Return any existing Action instance of this class  
  14.             instance = (Action) actions.get(className);//2、根据类名去map里查寻实例是否已经存在  
  15.             if (instance != null) {  
  16.                 return (instance); //3、如果存在,则直接返回  
  17.             }  
  18.   
  19.             // Create and return a new Action instance  
  20.             //4、如果不存在,则创建一个新实例  
  21.             instance = (Action) RequestUtils.applicationInstance(className)  
  22.   
  23.             instance.setServlet(this.servlet);  
  24.             actions.put(className, instance);//5、把创建好的action放到map里  
  25.         }  
  26.         …  
  27.         return (instance);  
  28.   
  29.     }  

我们再来看看actions的定义: 

Java代码  

  1. /** 
  2.  * The set of Action instances that have been created and 
  3.  * initialized, keyed by the fully qualified Java class name of the 
  4.  * Action class. 
  5.  */  
  6. protected HashMap actions = new HashMap();  

结论: 

struts1.2获取action的方式是单例的,所有的action都被维护在一个hashMap里,当有请求到达时,先根据action的名称去hashMap里查找要请求的Action是否已经存在,如果存在,则直接返回hashMap里的action。如果不存在,则创建一个新的Action实例。

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/yztezhl/article/details/44155287
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞