弹簧控制器 - 线程安全和存储资源

And*_*dna 5 java tomcat spring-mvc thread-safety

我对弹簧mvc和螺纹安全性有疑问.

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

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

@Controller
@RequestMapping("/manage")
public class QuestionManagementController {
Run Code Online (Sandbox Code Playgroud)

他有Singleton范围,所以来自每个用户的每个请求都使用相同的控制器.

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

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

2:控制器的作用域为 request

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

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

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

小智 5

一个很多参数可以被添加到控制器方法,如请求,会话,校长等,以避免您的问题.

通常有3层架构:

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

因此,根据你在DB中查询的内容,我建议有一个服务,如果命中数据库是昂贵的,每次你需要来自数据库的东西调用服务(即没有存储在控制器中的任何东西),由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.
    }
}
Run Code Online (Sandbox Code Playgroud)

在这里我使用principal和spring确保这是当前用户的一个.

参考文献:

请注意,这是否完全解决了您的问题