我有一个关于Spring 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访问)
所以,这取决于你在DB查询,我会建议有一个服务,由Spring与高速缓存注入,如果击中DB是昂贵的,每次你需要的东西,从数据库调用服务(即存储在控制器无类级)
简单例子,假设我们是落后弹簧安全,一切都需要一个完全登录的用户。 我们有一个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.
}
}
这里我用的本金和弹簧确保这是当前用户之一。
参考文献:
-
@Cachable
- 又见初始化独身Spring框架3 MVC
注知道这个答案完全对您的问题