spring控制器-线程安全性和存储资源


问题内容

我对spring mvc和线程安全性有疑问。

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

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

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

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

我想知道通常如何解决此问题:

1:控制器是通过Session作用域创建的吗?(但我认为,如果一个用户快速执行某些操作可能会导致控制器出现争用情况,那么也会出现问题)。

2:控制器的作用域为 request

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

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

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


问题答案:

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

通常有一个三层架构:

  • @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.
    }
}

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

参考:

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