Spring中的Controller是单例的(原因和问题)

在Spring3中,Controller默认是单例的。如果Controller中有个私有的变量a,那么所有请求到Controller中,使用的a变量是共用的。即某个请求要是修改了这个变量a,那么在别的请求中也是可以读到这个修改的内容的。

若是在@controller之前增加@Scope("prototype"),就可以改变单例模式为多例模式。

package com.xcesys.extras.webapp.controller.system; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller @RequestMapping(value = "admin/system/example") public class ExampleAction { //定义一个变量 private int singletonInt = 1; @RequestMapping(value="/test") @ResponseBody public String singleton(HttpServletResponse response,HttpServletRequest request){ String data = request.getParameter("data"); if(data != null && data.length()>0){ int paramInt = Integer.parseInt(data); singletonInt = singletonInt + paramInt; }else{ singletonInt+=1000; } return String.valueOf(singletonInt); } } 输入:http://localhost:8080/a/admin/system/example/test?data=15 输出的结果是:

第一次: singletonInt=15

第二次: singletonInt=30

第三次: singletonInt=45

从以上结果可以得知,singletonInt的状态是共享的,因此Controller是单例的。
问题: 如果Controller类是单例,那么多个线程请求同一个Controller类中的同一个方法,线程是否会堵塞

@RequestMapping(value="/sleep")
	@ResponseBody
	public String switcher(HttpServletRequest request,HttpServletResponse response) throws InterruptedException{
		String sleep = request.getParameter("sleep");
		if(sleep.equals("on")){
		    Thread.currentThread().sleep(1000);
			return "sleep on";
		}else{
			return sleep;
		}
	}

验证方法:分别发送两个请求,

第一个请求:http://localhost:8080/a/admin/system/example/sleep?sleep=on

第二个请求:http://localhost:8080/a/admin/system/example/sleep?sleep=test

验证结果:第一个请求发出去以后,本地服务器等待100s,然后返回结果"sleep on",在本地服务器等待的者100s当中,发送第二个请求,直接返回结果"test"。说明之间的线程是不互相影响的。

为什么SpringMVC 要设计成单例模式的呢?

   Spring的Bean作用域有5个:   

        1.  singleton  单例模式,当spring创建applicationContext的时候,spring会初始化所有的该作用域实例,加上lazy-init就可以避免

        2.  prototype  原型模式,每次通过getBean获取该Bean就会产生一个实例,创建之后spring将不再对其进行管理

        3.  request    每次请求都会产生一个请求域,spring依旧对其监听

        4.  session   同上

        5. global Session 全局web域,类似servlet的application


 

1、为了性能。 

2、不需要多例(上面的demo已经说明,在使用单例的时候,会改变其设定的变量)


最佳实践:

1、不要在controller中定义成员变量。(在工作中的程序设定,是绝对不允许的)

2、万一必须要定义一个非静态成员变量时候,则通过注解@Scope("prototype"),将其设置为多例模式。




      

你可能感兴趣的:(Spring,MVC)