5

我有一个关于 spring mvc 和线程安全的问题。

我们正在开发将存储在 tomcat 上的 Web 应用程序。如果我理解正确,Tomcat 会为每个请求创建线程并且它有一些线程池。现在,调度程序 servlet 在请求之间共享,并且可能是线程安全的。

但是当我这样创建控制器时:

@Controller
@RequestMapping("/manage")
public class QuestionManagementController {

他有Singleton范围,因此来自每个用户的每个请求都使用相同的控制器。

我想知道这个问题通常是如何解决的:

1:控制器是用Session范围创建的吗?(但我认为,如果一个用户快速执行一些可能导致控制器出现竞争条件的事情,也可能会出现问题)。

2:控制器的范围为request

3:创建在类级别不共享任何变量的无状态控制器,或者让它们处于只读模式

或者也许有一些更好的“最佳实践”可以解决这类问题。

我在问这个问题,因为现在我们将它们作为Singleton作用域,并且存在一个问题,即在大多数方法中,我们在数据库中查询用户,并且由于作用域的原因,我们无法将此信息存储在类级别变量中。我们可以尝试使用一些线程安全的集合,但稍后可能会有其他资源需要同步访问。

4

1 回答 1

5

许多参数可以添加到控制器方法中,如请求、会话、主体等,以避免您的问题。

通常有 3 层架构:

  • @Controller(他们委托服务)
  • @Service(他们使用 DAO 或存储库完成工作)
  • @Repository(或 DAO,他们进行数据库访问)

因此,根据您在数据库中查询的内容,我建议您使用 Spring 注入缓存的服务,如果访问数据库成本高昂并且每次您需要数据库中的内容时调用服务(即控制器中没有存储任何内容)班级水平)

一个简短的例子,假设我们支持 spring-security 并且一切都需要一个完全登录的用户。我们有一个userData表,其中键是用户登录,我们有一个 url/data来获取显示我的用户数据的页面:

@Controller
@RequestMapping("/data")
public class UserDataController
{
    @Autowired
    private UserService userService;

    @RequestMapping(value = "", method = RequestMethod.GET)
    public ModelAndView data(final Principal principal) {
        Assert.notNull(principal); // throw if assertion fails
        Assert.hasText(principal.getName());

        final UserData userData = this.userService.findByUserName(principal.getName());
        Assert.notNull(userData, "userData not found");

        return new ModelAndView("userData", "userData", userData);
    }
}

@Service("userService")
public class userService 
{
    private static final String USERDATA_CACHE = "com.acme.foo.UserData";

    @Autowired
    private UserDataRepository userDataRepository;

    @Cacheable(USERDATA_CACHE)
    public UserData findByUserName(final String userName) {
        return this.userDataRepository.findByUserName(userName);
    }
}

@Repository
public class UserDataRepository
{
    // or use spring-data-jpa

    public UserData findByUserName(final String userName) {
        // query table userData and create an UserData from results.
    }
}

在这里,我使用主体和弹簧确保这是当前用户之一。

参考:

请注意确定此答案是否完全符合您的担忧

于 2012-08-25T13:18:31.473 回答