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

Java Spring MVC 3用于@Autowired Singleton线程安全,java,google-app-engine,spring-mvc,thread-safety,singleton,Java,Google App Engine,Spring Mvc,Thread Safety,Singleton,好的,我有三层,分别来自MVC Spring 3设计中的控制器->服务->存储库。现在,我的问题是,既然默认范围被定义为Singleton,那么它们是线程安全的吗 代码如下所示: UserController.java @Controller @RequestMapping("/users") public class UserController extends ExceptionExtension { @Autowired private IUserService use

好的,我有三层,分别来自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";
              }
          }
     }
}
例如,用户A和用户B同时运行相同的url,但参数不同。
用户A请求=>”http://domain.com/users/update?user=myname1@域名“
用户B请求=>”http://domain.com/users/update?user=myname2@域名“

由于控制器是单例的,用户A电子邮件变量是否与用户B电子邮件变量重叠,反之亦然

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

==>

通过作用域(“请求”)到我的@Service层,我点击了以下错误消息:/

3328[main]错误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时出错:作用域“request”不可用 激活当前线程;考虑定义范围代理 如果您打算从单例引用它,则使用此bean;嵌套 异常为java.lang.IllegalStateException:没有线程绑定请求 已找到:您是指实际应用程序之外的请求属性吗 web请求,或在原始 接收线程?如果您实际在web请求中操作 并且仍然收到此消息,您的代码可能正在外部运行 DispatcherServlet/DispatcherPortlet:在这种情况下,使用 RequestContextListener或RequestContextFilter公开当前 请求


在这里,线程安全取决于作用域
singleton

这就是最终发生的情况=>相同的
userSpace
bean用于两个请求,并且两个请求同时访问
userService
bean。因此
IUserService
需要是线程安全的,才能使整个操作正常执行

将范围设置为
请求


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

中进行相应的编码,如果您创建任何层作用域:原型,就像注释中建议的那样,您只是将问题再次转移到下面的层

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

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


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

我在UserService中没有私有变量,但它@Autowired到IUserManager respository。因此,基本上我需要添加作用域(“请求”)到服务层和存储库层?IUserService的作用域请求导致?有IUserServiceYea的作用域请求,线程安全对于单例设计非常重要。否则,一切都会一团糟…感谢您回复我的帖子。显然,您看到我的代码在控制器、服务和存储库类中没有任何实例变量。我的实现是使用MVC Spring 3的Google App Engine。我不确定MVC Spring能否帮助我在服务层处理事务。因此,我在数据存储/存储库层实现了事务,因为我遵循Google App Engine示例进行编码。我真正担心的是我在第一篇文章中提到的并发更新问题。我只是nt以确保数据不会从用户处相互交叉。我还有一个关于Autowired变量的问题。类中的Autowired变量是否被视为实例变量?是的,因此,除非该对象的方法以线程安全的方式实现,否则它将受制于竞争条件。我编辑了我的答案,以考虑您使用google的因素appengine,它完全改变了一切。我有自己的方法来控制存储库层的事务。到目前为止,一切都很好。GAE提到了线程安全,但它的线程安全只适用于静态方法。虽然我用非静态方法对所有层进行编码,我认为它们只是非线程安全。问题是当类Autowired变量同样是一个实例变量时,我必须在类变量实例化时更改请求的范围。我读了很多Objectify。我认为这很好,但我仍然更喜欢用我自己的Google Data Store低级API方法(例如UserManager)控制存储库层。
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;
        }
    }
}