java spring mvc 线程安全

2017-04-26 11:41

在spring 框架当中,默认每个bean 都是scope=”singleton”单例模式。即是只在首次创建该类的实例,之后所用引用的该bean,其实都是首次创建的实例。
所以当多个线程同时操作该bean的时候,就有可能出现线程不安全的情况(主要体现在该bean拥有属性,且在运行中会更改该属性的时候)。
spring mvc 中如果我们没有对该类进行修饰指定的话,也默认是scope=”sington”单例模式。如果该类存在着自我属性的话也容易触发线程安全问题,从而导致出现脏数据的情况。
那么,我们怎么去解决这个问题呢?
1、spring mvc 官方推荐我们使用单例模式,因为单例模式下不用用户每次请求都重新生成一个实例,所以性能很好。所以我们应避免在bean中定义属性
2、如果项目需求需要定义属性,那么我们就需要更改scope=”sington”单例模式为scope=”prototype”原型模式,这种模式在每次引用该bean的时候都会重新生成一个该bean的对象,所以不会存在线程安全问题了。还有一种模式,是spring针对web开发衍生的scope=”request”模式,这种模式是将实例保存在request作用域中,所以每个请求即是每个线程都有独自属于自己的bean 也是线程安全,但是针对前一个scope=”prototype” 安全性没有那么高,为啥?因为是保存在request作用域中的。所以除了首次调用会生成该实例,之后每次调用都是从request作用域中取出来的,而不像scope=”prototype”每次调用都会实例化一个新的对象给你。

package spring.beans.service;


@Service("service_demo")
@Scope("request")
public class DemoService
{

}
import spring.beans.service.DemoService;

@Service
@RequestMapping("Demo2")
@Scope("request")
public class Demo2Controller
{
    @Resource(name="service_demo")
    private DemoService demoService;

    @RequestMapping(value="index",method=RequestMethod.GET,produces="text/html;charset=utf-8")
    @ResponseBody
    public String getIndex()
    {
        return "hello world";
    }
}

如上,将类DemoService 修饰@Scope(“request”)那么每次用户请求都会生成该类的实例,之后,不管是在哪一个组件下面调用都不会再生成该类的实例,而是直接引用保存在request作用域中的实例。当然,你重新加载了这个类并实例化除外,只能是通过spring 去调用交给spring去处理。如我就喜欢将数据库连接和操作写成request作用域,每个用户请求生成一个数据库连接,当用户关闭页面后就通过@PreDestroy修饰的方法去关闭数据库连接。