java - Spring Controller - 线程安全和存储资源

标签 java tomcat spring-mvc thread-safety

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

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

但是当我这样创建 Controller 时:

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

他有 Singleton 作用域,因此来自每个用户的每个请求都使用同一个 Controller 。

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

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

2: Controller 的作用域为request

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

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

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

最佳答案

A lot of parameters can be added请求、 session 、委托(delegate)人等 Controller 方法以避免您的问题。

通常有一个三层架构:

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

因此,根据您在数据库中查询的内容,我建议提供一项服务,如果访问数据库的成本很高,则由 Spring 注入(inject)缓存,并且每次您需要数据库中的内容时都调用该服务(即没有存储任何内容)在 Controller 类级别)

一个简短的例子,假设我们支持 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.
    }
}

这里我使用 principal 和 spring 确保这是当前用户一。

引用:

请注意这个答案是否完全解决了您的问题

关于java - Spring Controller - 线程安全和存储资源,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12121519/

相关文章:

java - 注释属性 RequestMapping.value 的值必须是常量表达式

java - spring webflow提交带有新项目的数组

java - 当 AutoCompleteTextView 获得焦点时隐藏元素

java - 应该如何将 tomcat 与现有项目一起使用?

javascript - 服务器关闭后,如何让 JavaScript 函数继续运行?

Java Bean创建异常

java - 如何使用注释将作业参数传递给项目处理器

java - 如何通过反射获取这个Method对象?

java - 多次初始化时 for 循环出错

java - 通过 Ant 运行测试时出现 NoClassDefFoundError 但在 Tomcat 中部署时工作正常