1.Spring框架Bean与controller安全问题与其作用域
Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”。但是Spring框架创建bean对象,在默认情况却并没有保证这些对象的线程安全,需要由开发者自己编写解决线程安全问题的代码。
Spring框架默认使用单例模式,只有一个共享实例存在,每次对这个bean的请求都会返回这个唯一的实例,并且交给IOC容器帮助我们管理这些唯一的bean,这样可以大大的节省性能。
但是由于是单例,如果我们在controller 中定义成员变量时(当进行多线程访问controller 时,成员变量会在多个线程之间出现数据混乱),或者单例中存在竞争关系,线程安全问题将会毫无疑问的暴露出来。所以我们不应该在bean中声明任何有状态的实例变量或类变量,如果你非要那么做,那么应该把变量变为线程私有,可以使用ThreadLocal 。如果还想共享变量,可以使用synchronized(具体可以看看其他技术文章) 。还有一种方式解决,我们需要看一下bean标签里面scope属性,把它变成多例模式,但是会影响性能.
同时Spring对每个bean的bean标签提供了一个scope属性来表示该bean的作用域 ,它同样也是bean的生命周期。 如果一个bean的scope属性为默认的singleton ,那么在第一次被注入时,会创建为一个单例对象,该对象会一直被重复使用直到这个功能结束,不在使用。
scope属性(bean的作用域):
-
singleton:默认属性, 这个bean会被定义为一个单例对象,第一次被注入时,会创建为一个单例对象,该对象会一直被重复使用直到这个功能结束,该对象的生命周期是与Spring IOC容器 。
-
prototype:bean会在每次注入时都会创建一个新的对象
-
request:bean会在每个HTTP请求中创建一个单例对象,也就是说在单个请求中都会复用这一个单例对象。
-
session:bean会在一个session的生命周期内创建一个单例对象
-
application:bean会为在ServletContext的生命周期中复用一个单例对象。
-
websocket:bean会为在websocket的生命周期中复用一个单例对象。
在scope的属性中,可以看到一个prototype的属性,每次注入(请求这个bean)时都会产生一个全新的bean供我们使用。我们可以把它变成一个多例模式