先看这么一段代码:

@Service
public class AccountService {
private String message; public void foo1() {
if (true) {
this.message = "a";
} else {
this.message = "b";
}
} public void foo2() {
// 改动this.message的代码...
// ... ...
}
}

假设你打算在@Controller里这么调用AccountService :

accountService.foo1();
model.addAttribute(accountService.getMessage());

那么就有线程安全的危急了。

问题原因

在Spring中。bean的默认scope是singleton,也就是说容器中仅仅有一个bean的实例。而在Java Web环境中,webserver会为每个请求创建一个线程来处理它。这样一来。在@Controller中调用@Service bean的方法就会导致有多个线程在运行@Service方法。比如线程A在运行foo1()方法,线程B在运行foo2()方法。

那么问题来了,多个线程同一时候读写message成员变量。就可能让getMessage()方法返回错误的值


解决方法

1. 将@Service bean的scope改为 "request",即:
@Service
@Scope("request")
public class AccountService {
private String message;

这样Spring会为每个请求分别创建一个AccoutService对象,每个线程都有自己的message变量。就不会出错了。

但坏处是创建@Service bean的开销往往比較大,会导致程序性能下降。


2. 使用不可变对象(Immuable Object)封装message变量
定义例如以下类:
class MessageWrapper {
private String message; public MessageWrapper(String msg) {
this.message = msg;
} // 仅仅提供get方法
public String getMessage() {
return this.message;
}
}

AccountService的foo1()方法改动例如以下:

@Service
public class AccountService {
public MessageWrapper foo1() {
if (true) {
return new MessageWrapper("a");
} else {
return new MessageWrapper("b");
} // ... ...
}

这样便能够完美避免线程安全问题,又不会带来过多的额外开销。

Spring MVC不要在@Service bean中保存状态的更多相关文章

  1. [翻译]Spring MVC RESTFul Web Service CRUD 例子

    Spring MVC RESTFul Web Service CRUD 例子 本文主要翻译自:http://memorynotfound.com/spring-mvc-restful-web-serv ...

  2. 程序中保存状态的方式之Cookies

    程序中保存状态的方式之 Cookies,之前写过一篇关于ViewState的.现在继续总结Cookies方式的 新建的测试页面login <%@ Page Language="C#&q ...

  3. 程序中保存状态的方式之ViewState

    程序中保存状态的方式有以下几种: 1.Application 2.Cookie 3.Session 4.ViewState:ViewState是保存状态的方式之一,ViewState实际就是一个Hid ...

  4. 在C 函数中保存状态:registry、reference和upvalues

    在C函数中保存状态:registry.reference和upvalues      C函数能够通过堆栈来和Lua交换数据,但有时候C函数须要在函数体的作用域之外保存某些Lua数据.那么我们想到全局变 ...

  5. Spring MVC page render时jsp中元素相对路径的解决办法

    前段时间做了用Spring Security实现的登录和访问权限控制的功能,但是page render使用的是InternalResourceResolver,即在spring的servlet配置文件 ...

  6. spring MVC 管理HttpClient---实现在java中直接向Controller发送请求

    在spring MVC中,大多数时候是由客户端的页面通过ajax等方式向controller发送请求,但有时候需要在java代码中直接向controller发送请求,这时可以使用HttpCilent实 ...

  7. spring mvc 接收表单 bean

    spring MVC如何接收表单bean 呢? 之前项目中MVC框架一直用struts2,所以我也就按照struts2 的思维来思考 页面loginInput.jsp: <?xml versio ...

  8. spring mvc 数据校验(bean实体注解实现)

    spring mvc 数据校验 1.添加个jar (jar与一版本会冲突) <dependency> <groupId>com.fasterxml</groupId> ...

  9. 利用Spring MVC搭建REST Service

    之前写过一篇 利用JAX-RS快速开发RESTful 服务 今天来看下spring-mvc框架如何实现类似的功能: 一.pom.xml <?xml version="1.0" ...

随机推荐

  1. 认知升级x

    写作目的 今天公司组织了一场关于认知升级的培训讲座,请的主管运营和发行的VP大神,收获颇多,亟待消化.这篇文章可以作为自己课后的一个笔记,自己可以反思,进而同步至团队,大家共同成长. 对于机会的认识 ...

  2. /etc/auto.master - automounter的主映射文件

    描述(DESCRIPTION) 当机器启动自动挂载器时, autofs(8) 脚本就会查寻 auto.master 这个主映射文件.文件中的每行分别指明,一个挂载点以及与对应的需要被挂载的文件系统.通 ...

  3. C++中何时使用引用

    使用引用参数的原因: 程序员能够修改调用函数中的数据对象 通过传递引用而不是整个数据对象,可以提高程序的运行速度. 当数据对象较大时(如结构和类对象),第二个原因最重要,这些也是使用指针参数的原因.这 ...

  4. ztree 样式修改 white-space: nowrap; 后 下划线要是跟上的话 宽度 width 要 auto 就自动更新了

    width:auto; border-bottom:1px solid #ccc; height:30px; display: inline-block;white-space: nowrap;

  5. Adobe Dreamweaver CC 2014 代码颜色目录 dw

    他的颜色代码配置文件,不在安装目录下,这让我好找啊~ C:\Users\Administrator\AppData\Roaming\Adobe\Dreamweaver CC 2014\zh_CN\Co ...

  6. CAD交互绘制直线(com接口)

    用户可以在控件视区任意位置绘制直线. 主要用到函数说明: _DMxDrawX::DrawLine 绘制一个直线.详细说明如下: 参数 说明 DOUBLE dX1 直线的开始点x坐标 DOUBLE dY ...

  7. 瀑布流布局js

    <!DOCTYPE html><html><head> <meta http-equiv="Content-Type" content=& ...

  8. Python 函数对象-函数嵌套-名称空间与作用域-闭包函数

    今日内容: 1. 函数对象 函数是第一类对象: 指的是函数名指向的值可以被当中数据去使用 1.可以被引用 2.可以当做参数传给另一个函数 3.可以当做一个函数的返回值 4.可以当做容器类型的元素 2. ...

  9. [Python3网络爬虫开发实战] 6.3-Ajax结果提取

    这里仍然以微博为例,接下来用Python来模拟这些Ajax请求,把我发过的微博爬取下来. 1. 分析请求 打开Ajax的XHR过滤器,然后一直滑动页面以加载新的微博内容.可以看到,会不断有Ajax请求 ...

  10. 把wav文件等时长切割

    ffmpeg -i somefile.mp3 -f segment -segment_time 1800 -c copy out%03d.mp3 segment_time 是切割时长,单位秒