弹簧控制器 – 线程安全和存储资源
我对弹簧mvc和螺纹安全性有疑问。
我们正在开发将存储在tomcat上的Web应用程序。 如果我理解正确,Tomcat会根据请求创建线程并且它有一些线程池。 现在,调度程序servlet在请求之间共享,可能是线程安全的。
但是当我创建这样的控制器:
@Controller @RequestMapping("/manage") public class QuestionManagementController {
他有Singleton
范围,因此来自每个用户的每个请求都使用相同的控制器。
我想知道这个问题通常是如何解决的:
1:是使用Session
范围创建的控制器吗? (但我认为如果一个用户快速做一些可能导致控制器竞争条件的事情,也可能会出现问题)。
2:控制器的范围是request
3:创建无状态控制器,这些控制器不在类级别共享任何变量,或者将它们置于只读模式
或者也许有一些更好的“最佳实践”可以解决这类问题。
我问这个问题,因为现在我们将它们作为Singleton
作用域,并且存在一个问题,即在大多数方法中我们在数据库中查询用户,并且由于范围我们无法将此信息存储在类级变量中。 我们可以尝试使用一些线程安全的集合,但后来可能有其他资源需要同步访问。
可以将许多参数添加到控制器方法,如请求,会话,主体等,以避免您的问题。
通常有3层架构:
-
@Controller
(他们委托服务) -
@Service
(他们使用DAO或存储库完成工作) -
@Repository
(或DAO,他们进行数据库访问)
因此,根据你在DB中查询的内容,我建议有一个服务,如果命中数据库是昂贵的,每次你需要来自数据库的东西调用服务(即没有存储在控制器中的东西),由Spring注入一个缓存class级)
一个简短的例子,假设我们落后于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确保这是当前用户的一个。
参考文献:
-
@Cachable
- 另请参阅Spring Framework 3 MVC中的Initialize Singletons
请注意,这个答案是否完全符合您的疑虑