先看这么一段代码:

@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. 【Lucene】实现全文索引

    2. Lucene 实现全文检索的流程2.1.索引和搜索流程图 绿色表示索引过程,对要搜索的原始内容进行索引构建一个索引库,索引过程包括:确定原始内容即要搜索的内容 -> 采集文档 -> ...

  2. react link引入外部css样式的坑

    刚开始的代码是这样的,使用react router4.x写的demo路由跳转后,页面的没有渲染,是因为没有引入外部css文件(或者说引入外部文件路径错误) <!DOCTYPE html> ...

  3. bat copy

    @echo off regedit /s %~dp0regedit.reg                                          //注册注册表xcopy "D: ...

  4. PHP笔录(韩顺平)

    这里记录下韩顺平视频学习记录 http://www.php.cn/code/11753.html

  5. 14Spring通过注解配置Bean(2)

    下面将对13Spring通过注解配置Bean(1)的中Repository.Service.Controller通过注解方式来建立关联. <context:component-scan>元 ...

  6. eclipse perl配置

    先下载jdk,如果jdk装的是32位,eclipse也要下载32位的,64位也是一样.我用的是jdk7 64位. 下载eclipse,去官网上下载最新的http://www.eclipse.org/d ...

  7. os系统安装Python虚拟环境virtualenv和virtualenvwrapper

    一.安装Python 上节已经讲了如何安装Python2和Python3 二.给Python3安装virtualenv 在终端输入:sudo pip3 install virtualenv 等待安装成 ...

  8. Qt5笔记之数据库(五)SQL表格模型QSqlTableModel

    教程网址:http://www.qter.org/portal.php?mod=view&aid=57 0.打开tablemodel.pro文件,加上: QT += coregui sql 注 ...

  9. docsearch & algolia

    docsearch & algolia The easiest way to add search to your documentation. https://community.algol ...

  10. hdu 1251简单字典树

    #include<stdio.h> #include<iostream> #include<string.h> using namespace std; struc ...