使用 spring-session 获取当前会话

Get the current session with spring-session

这是我的问题:我正在编写一个平台,我将提供给客户来实施他们的项目。因此,在我的平台中,我创建了一个 SessionService,其中包含 getCurrentSessiongetAttributesetAttribute 等方法。在 spring-session 之前,我的 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 对象从我的控制器传递到我的外观,再传递到非常靠近数据库层的服务层。这对我来说似乎是一个非常糟糕的主意,所以我的问题是:有没有办法让 currentSession 靠近 db 层?我认为的一种方法是编写一个将调用控制器的拦截器,它将在存储库或服务中设置当前会话?我只是不确定这是正确的方法。

从服务层获取Session Id

您可以使用 RequestContextHolder 检索会话 ID、设置属性和删除属性。

RequestContextHolder 通常使用 RequestContextListenerRequestContextFilter 设置。 Spring 会话不适用于 RequestContextListener,因为 Spring 会话无法在调用 RequestContextListener 之前包装请求。

不幸的是,这意味着对于 Spring 引导应用程序,RequestContextHolder 无法开箱即用。要解决这个问题,您可以创建一个 RequestContextFilter Bean。有关此问题的更新,请参阅 spring-boot/gh-2637

我应该把它放在会话中吗?

仅仅因为很容易将很多对象放在会话中并且存储在 Redis 中并不意味着这样做是正确的。

请记住,每次请求都会检索整个会话。因此,尽管 Redis 速度很快,但如果会话中有很多对象,这可能会产生重大影响。显然可以针对您的情况优化实现,但我认为会话的概念通常持有这种属性。

一般的经验法则是,"Do I need this object for over 95% of my requests?"(将此视为我的几乎所有请求)。如果是这样,它可能是会话的候选者。在大多数情况下,如果对象符合此条件,则它应该是安全相关的。

是否应该从服务层的ThreadLocal获取session id?

这当然是有争议的,因为代码既是一门科学,也是一门艺术。

但是,我认为您不应该在整个体系结构中从线程区域设置变量中获取会话 ID。这样做感觉有点像从ThreadLocale中的HttpServletRequest获取一个"Person id"和获取当前的"Person id"。相反,应该从控制器获取值并将其传递到您的服务层。