Spring中的Scope

说明

  1. Singleton :一个Spring 容器中只有一个Bean 的实例,此为Spring 的默认配置,全容器共享一个实例。
  2. Prototype :每次调用新建一个Bean 的实例。
  3. Request: Web 项目中,给每一个http request 新建一个Bean 实例。
  4. Session: Web 项目中,给每一个http session 新建一个Bean 实例。
  5. Global Session :这个只在portal 应用中有用,给每一个global http session 新建一个Bean

设置方法

可以在类顶部添加@Scope注解,类似这样:

1
2
3
4
@Service
@Scope("prototype")
public class DemoPrototypeService {
}

注意:如果你想将Scope设置为request或者session,那么需要这样设置:

1
2
3
4
@Service
@Scope(value= WebApplicationContext.SCOPE_REQUEST, proxyMode= ScopedProxyMode.TARGET_CLASS)
public class DemoPrototypeService {
}

其中的proxyMode= ScopedProxyMode.TARGET_CLASS一定不能省,具体原因可以查看《Spring实战》86页的说明。且注意接口和实现类,要添加的proxyMode值是不一样的。

另外,注意import的类别引错了,是import org.springframework.context.annotation.Scope;这个类。之前我就出现引入了错误的类,导致提示我Scope属性设置不对的问题。

Spring中的单例Bean,生命周期有多长?

Bean对象在程序启动时,会被Spring容器初始化,调用构造方法进行创建,然后就一直位于Spring容器中;而Spring容器的生命周期是和JVM进程一致的,因此这些Bean对象的生命周期,也是和JVM是相同的。

简而言之:默认的单例模式下,不同的请求,用到的都是同一个Bean对象

因此如果你将一个Bean类设置为单例,则不应该在里面保存一些可能发生变更的属性,除非是你有明确的需求必须这样做。否则不同用户的请求,可能会修改这些属性,导致你取到的属性值和你预期的不一致。

为了验证,写了一个demo。

Service类:

1
2
3
4
5
6
7
8
9
10
11
@Service
public class CounterService {

private int number = 0;

public void count()
{
number ++;
System.out.println("number = " + number);
}
}

Controller类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Controller
@RequestMapping("/test")
public class TestController {


@Autowired
A a;

@Autowired
CounterService counterService;

@RequestMapping("/count")
public ResponseEntity count()
{
counterService.count();

return new ResponseEntity(HttpStatus.OK);
}
}

然后启动程序,浏览器调用4次接口,控制台输出内容如下:

1
2
3
4
number = 1
number = 2
number = 3
number = 4

说明在不同请求中,调用的都是同一个Bean对象,其属性才能被保存起来,不断增加。