用于@Autowired Singleton线程安全的Spring MVC 3

时间:2012-11-26 15:53:33

标签: java google-app-engine spring-mvc thread-safety singleton

好吧,我有来自Controller-> Service->存储库的3层MVC Spring 3设计。现在,我的问题是,由于默认范围定义为Singleton,它们是否是线程安全的?

以下代码如下:

UserController.java

@Controller
@RequestMapping("/users")
public class UserController extends ExceptionExtension {
     @Autowired
     private IUserService userService;

     @RequestMapping(value = { "/update", "/update/" }, method = RequestMethod.GET)
     public String updateUser(@RequestParam("email") String eMail, ModelMap model)
        throws Exception {

          if (eMail.isEmpty() || eMail == null) {
              throw new ArgumentIsEmptyException("Required String parameter 'email' is empty");
          } else {
              UserModel userModel = userService.setUser(eMail);

              if (userModel != null) {
                  model.put("roleList", userService.setRoleList());
                  model.put("title", "Update Existing User");
                  model.put("post", "/users/post/update");
                  model.put("userForm", userModel);

                  return "users.update";
              } else {
                  model.put("title", "Update Existing User");
                  model.put("result", "<font color='red'><u>" + eMail + "</u> does not exist in the database.</font>");
                  model.put("flag", "Error");

                  return "users.result";
              }
          }
     }
}

UserService.java

public class UserService implements IUserService {

    @Autowired
    private IUserManager userManager;

    public UserModel setUser(String eMail) {
        UserModel userModel = new UserModel();
        Entity userEntity = userManager.getUser(eMail);

        if (userEntity != null) {
            userModel.setEMail(eMail);
            userModel.setRole(userEntity.getProperty("role").toString());
            userModel.setEnable((Boolean)userEntity.getProperty("enable"));

            return userModel;
        } else {
            return null;
        }
    }
}

说,用户A和用户B同时运行相同的URL但参数不同 用户A请求=&gt; “http://domain.com/users/update?user=myname1@domain.com”。
用户B请求=&gt; “http://domain.com/users/update?user=myname2@domain.com”。

由于Controller是单例,用户A eMail变量是否会与用户B重叠,反之亦然?

我发现很难理解Singleton Thread-Safe在这种情况下是如何工作的。我的@Service和@Repository是否应该声明为@Scope(“prototype”),以便内部方法变量与新的实例化隔离?

====&GT;

使用Scope(“request”)到我的@Service层,我发出了以下错误信息:/

  

3328 [main] ERROR org.springframework.web.context.ContextLoader -   上下文初始化失败   org.springframework.beans.factory.BeanCreationException:错误   创建名为'roleController'的bean:注入自动装配   依赖失败;嵌套异常是   org.springframework.beans.factory.BeanCreationException:不能   autowire字段:private com.company.dashboard.service.IRoleService   com.company.dashboard.controller.RoleController.roleService;嵌套   异常是org.springframework.beans.factory.BeanCreationException:   创建名为'roleService'的bean时出错:范围'请求'不是   当前线程有效;考虑为。定义范围代理   如果你打算从单身中引用它,这个bean;嵌套   异常是java.lang.IllegalStateException:没有线程绑定请求   发现:您是指实际的请求属性吗?   Web请求,或处理原始请求之外的请求   接收线程?如果您实际在Web请求中操作   并且仍然收到此消息,您的代码可能正在外面运行   DispatcherServlet / DispatcherPortlet:在这种情况下,请使用   RequestContextListener或RequestContextFilter公开当前   请求。

2 个答案:

答案 0 :(得分:1)

此处线程安全取决于范围userService

singleton的内部锁定

这是最终发生的事情=&gt;两个请求使用相同的userSpace bean,并且两个请求同时访问userService bean。因此IUserService需要线程安全,才能使整个操作运行良好。

  

将范围设为request

在这种情况下,为每个请求分配一个新bean,由于线程限制,整个操作是线程安全的。如果您在IUserSpace

中进行了相应的编码

答案 1 :(得分:0)

如果您制作任何图层范围:原型,就像评论中建议的那样,您只是将问题再次移到下面的图层。

您需要决定交易划分的位置。通常,这是在对服务的调用级别完成的。 Spring可以为你处理。

控制器,服务和存储库通常应以无状态方式实现,也就是说这些类没有您的方法修改的任何实例变量。否则你将变得容易受到竞争条件的影响。最后,您的数据存储区必须支持使用事务。

您使用Google Appengine数据存储区。与任何RDBMS不同,它有一种非常具体的事务处理方法。要从Java应用程序与appengine交谈,我建议'Objectify'。首先阅读[关于它的概念](以及底层BigTable数据存储的概念1