在使用spring创建bean的时候需要在指定bean的生命周期,bean的声明周期有一下几种:
- singleton 表示在spring容器中的单例,通过spring容器获得该bean时总是返回唯一的实例
- prototype表示每次获得bean都会生成一个新的对象
- request表示在一次http请求内有效(只适用于web应用)
- session表示在一个用户会话内有效(只适用于web应用)
- globalSession表示在全局会话内有效(只适用于web应用)
在多数情况,我们只会使用singleton和prototype两种scope,如果在spring配置文件内未指定scope属性,默认为singleton。
我们都知道在平时的开发中如果没有特殊的要求一般是使用默认即singleton。如果变量或者存储集合定义的位置不当会影响数据的完整性和正确性。当使用singleton时一个请求开始到返回经历过程如下:当创建spring工厂时创建声明周期为singleton的bean对象(prototype是在调用getBean方法时创建bean对象),并且会在整个程序的生命周期中一直使用该对象。如果获取一个http请求,spring会为改请求开辟一个新的线程来处理业务,当有多个请求时,在spring中存在多个线程共享该一个对象实例的情景。所以对于该实例对象来说其成员变量是线程不安全的(如果不加任何线程安全的操作的话)。所以我们在写代码时要把一些业务代码写在方法内部。因为当一个线程在执行某个方法时在内存中的过程对应着入栈和出栈的操作,即执行某个方法时会在该线程的线程栈中压入一个栈帧,执行完会在该线程栈中弹出一个栈帧,这些操作是线程内部的操作,不存在线程安全的问题,所以保证了业务数据的完整性。
代码:
action的定义:
private List<String> list = new ArrayList<String>();//该对象是多线程共享的,即多个请求用的是同一个list。
@RequestMapping("/main")
public ModelAndView main() {
list.add("a");
System.out.println("长度是:"+list.size());//每次请求list的长度会加1因为该变量是多线程共享的
System.out.println("当前访问的线程:"+Thread.currentThread().getName());//每次请求会是一个新的线程
System.out.println("当前产生的对象:"+this);//产生的是同一个对象
int i=0;i++;//在线程内部私有,不存在线程安全问题
System.out.println(i);
return new ModelAndView("/sso/roleproject");
}