这是我的问题:我正在编写一个平台,我将给予客户实施他们的项目。所以在我的平台上,我创建了一个SessionService
,其中我有getCurrentSession
,getAttribute
,setAttribute
等方法。在春季会议之前我的getCurrentMethod
看了像这样:
@Override
public HttpSession getCurrentSession() {
if (this.session == null) {
final ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
return attr.getRequest().getSession(true); // true == allow create
}
return this.session;
}
虽然它看起来很丑陋并且没有像redis这样的支持,但效果非常好。现在我想迁移到spring-session
,我希望使用SessionRepository
来查找用户的当前会话,但我只能看到getSession(String id)
。我相信id存储在cookie中,因此要使用它,我可能必须将HttpServletRequest
对象从我的控制器传递到我的外观,再到非常接近db层的服务层。这看起来对我来说是一个非常糟糕的主意,所以我的问题是:有没有办法让currentSession接近数据库层?我想的一种方法是编写一个将被调用控制器的拦截器,它将在存储库中设置当前会话,或者服务可能?我只是不确定这是正确的方法。
答案 0 :(得分:1)
从服务层获取会话ID
您可以使用RequestContextHolder
检索会话ID,设置属性和删除属性。
RequestContextHolder
通常使用RequestContextListener
或RequestContextFilter
进行设置。 Spring Session不能与RequestContextListener
一起使用,因为在调用RequestContextListener
之前,Spring Session无法包装请求。
不幸的是,这意味着对于Spring Boot应用程序,RequestContextHolder
无法开箱即用。要解决它,您可以创建一个RequestContextFilter
Bean。有关此问题的更新,请参阅spring-boot/gh-2637。
我应该把它放进会话吗?
仅仅因为在会话中放置大量对象并将其存储在Redis中并不意味着它是正确的做法。
请记住,每次请求都会检索整个会话。因此,当Redis速度很快时,如果会话中有很多对象,这会产生重大影响。显然,实现可以针对您的情况进行优化,但我认为会话的概念通常具有此属性。
一般的经验法则是,"我的95%以上的请求是否需要此对象?" (读这几乎是我的所有要求)。如果是这样,它可能是会话的候选人。在大多数情况下,如果符合此标准,则该对象应与安全相关。
我应该从服务层的ThreadLocal访问会话ID吗?
这肯定是开放的辩论,因为代码既是一门艺术,也是一门科学。
但是,我认为您不应该从整个架构中的线程区域设置变量中获取会话ID。这样做有点像获得一个" Person id"并获得当前"人员ID"来自ThreadLocale中的HttpServletRequest。相反,应从控制器获取值并将其传递到服务层。