先看这么一段代码:

@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. WNDCLASS和WNDCLASSEX

    typedef struct { UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HINST ...

  2. 13C++异常处理

    异常处理 14.1.1 异常处理的任务 程序编制者不仅要考虑程序没有错误的理想情况,更要考虑程序存在错误时的情况,应该能够尽快地发现错误,消除错误. 程序中常见的错误有两大类: 语法错误和运行错误.在 ...

  3. B3. Cocurrent 线程的状态

    [概述] 1). java.lang.Thread 类中定义了一个枚举 State, 定义了线程的六种状态:NEW.RUNNABLE.BLOCKED.WAITING.TIMED_WAITING.TER ...

  4. org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException 前言中不允许有内容 来自类路径资源的XML文档中的第1行是无效的

    今天复习一下Spring和Hibernate的整合,遇到了一个问题,报错信息如下: org.springframework.beans.factory.xml.XmlBeanDefinitionSto ...

  5. [转]Delphi调用cmd并取得输出文本

    //转自http://www.oschina.net/code/snippet_136241_3980 1 procedure CheckResult(b: Boolean); begin if no ...

  6. 1. 垃圾收集简介 - GC参考手册

    说明: 在本文中, Garbage Collection 翻译为 “垃圾收集”, garbage collector 翻译为 “垃圾收集器”; 一般认为, 垃圾回收 和 垃圾收集 是同义词. Mino ...

  7. List<> 集合 删除指定行

    不多说,直接上代码 public class Name { public string NameInfo { get; set; } } 删除值为Name2的行 static void Main(st ...

  8. Github ==〉本地(克隆)

    [情景] 新员工入职后,一般会将项目下载到本地. [下载(克隆)] 命令 git clone url地址 示例

  9. 【转】jquery 注册事件的方法

    原文链接:http://outofmemory.cn/code-snippet/2123/jquery-zhuce-event-method 1.使用事件名来绑定,可用的事件名有 change,cli ...

  10. golang函数指针的效果

    package main import ( "fmt" ) func fun1(key string) { fmt.Printf("fun11 key=%s\n" ...