使用 VaadinSession 的会话复制不起作用
Session replication with VaadinSession not working
我们有一个 Web 应用程序正在使用 Spring Boot (1.5) 和 Vaadin (7.7),并使用 Apache Shiro (1.4.0) 来确保安全。
应用程序配置为使用 DefaultWebSessionManager
让 Shiro 处理会话管理而不是 servlet 容器。
我们使用的是官方 Vaadin Spring 集成 (1.2.0),经过一些配置后一切正常。 VaadinSession
内部包含一个包装的 ShiroHttpSession
。
我们希望通过将 Shiro 配置为使用由外部 Cache
支持的 SessionDAO
来实现会话复制,这意味着会话得到(反)序列化。
一旦我们开始使用这个 SessionDAO
,Vaadin 就会崩溃并停止工作。当为了调试用内存中的 Map
替换外部缓存时,它再次工作。
这似乎是由 SpringVaadinServlet
引起的,因为它将 VaadinSession
存储为会话属性。 VaadinSession
是 Serializable
并且 Javadoc 显示:
Everything inside a VaadinSession should be serializable to ensure
compatibility with schemes using serialization for persisting the
session data.
VaadinSession
里面有一些不是Serializable
的字段,例如Lock
,里面的wrapped http session也被标记为transient。
正因为如此,Vaadin使用的session一分发就断掉,导致大量崩溃。
所以 VaadinSession
不是 在会话复制中实际可用?为什么会这样,我们如何解决这个问题?
注意:我们还有一个使用 Vaadin 8 的应用程序版本,这里发生了同样的事情。看来问题是由 Vaadin Spring 集成引起的。
Inside the VaadinSession are some fields that are not Serializable, for example a Lock and the wrapped http session inside is also marked as transient.
包装的 http 会话不是 Vaadin 会话的一部分,它是 http 会话。因此它是短暂的。 Lock 也是如此,它的实例存储在 http session 中。
为了正确实现会话序列化,您需要挂钩序列化事件并在反序列化会话时更新瞬变。 VaadinSession
应该用 VaadinService#loadSession
加载,它调用 VaadinSession#refreshTransients
.
Everything inside a VaadinSession should be serializable to ensure compatibility with schemes using serialization for persisting the session data.
此声明并不意味着您可以开箱即用地序列化您的应用程序。这只是意味着,如果您的应用程序也是可序列化的,那么通过精心设计,您可以序列化整个应用程序。
例如,出于性能原因,Vaadin 不会在每个可能的场合更新会话属性。有方法VaadinService#storeSession
。因此,您需要覆盖正确的方法或设置请求过滤器。例如。你可以在 VaadinService#endRequest
.
请注意,您需要使用粘性会话,以便通过适度的努力使其正常工作。如果您的会话在不同的机器上被反序列化,则可重入锁实例将无效。如果您希望能够在不同的机器上反序列化会话,则需要您的基础设施可以提供您可以使用的分布式锁,而不是 Java 的可重入锁并覆盖 Vaadin 的 getSessionLock
和 setSessionLock
方法来使用它。
进一步信息的宝贵来源:
Vaadin 首席技术官的一般说明
https://vaadin.com/blog/session-replication-in-the-world-of-vaadin
开发人员用一个堆栈完成的推荐
https://vaadin.com/learn/tutorials/hazelcast
另一位高级开发人员的想法
我们有一个 Web 应用程序正在使用 Spring Boot (1.5) 和 Vaadin (7.7),并使用 Apache Shiro (1.4.0) 来确保安全。
应用程序配置为使用 DefaultWebSessionManager
让 Shiro 处理会话管理而不是 servlet 容器。
我们使用的是官方 Vaadin Spring 集成 (1.2.0),经过一些配置后一切正常。 VaadinSession
内部包含一个包装的 ShiroHttpSession
。
我们希望通过将 Shiro 配置为使用由外部 Cache
支持的 SessionDAO
来实现会话复制,这意味着会话得到(反)序列化。
一旦我们开始使用这个 SessionDAO
,Vaadin 就会崩溃并停止工作。当为了调试用内存中的 Map
替换外部缓存时,它再次工作。
这似乎是由 SpringVaadinServlet
引起的,因为它将 VaadinSession
存储为会话属性。 VaadinSession
是 Serializable
并且 Javadoc 显示:
Everything inside a VaadinSession should be serializable to ensure compatibility with schemes using serialization for persisting the session data.
VaadinSession
里面有一些不是Serializable
的字段,例如Lock
,里面的wrapped http session也被标记为transient。
正因为如此,Vaadin使用的session一分发就断掉,导致大量崩溃。
所以 VaadinSession
不是 在会话复制中实际可用?为什么会这样,我们如何解决这个问题?
注意:我们还有一个使用 Vaadin 8 的应用程序版本,这里发生了同样的事情。看来问题是由 Vaadin Spring 集成引起的。
Inside the VaadinSession are some fields that are not Serializable, for example a Lock and the wrapped http session inside is also marked as transient.
包装的 http 会话不是 Vaadin 会话的一部分,它是 http 会话。因此它是短暂的。 Lock 也是如此,它的实例存储在 http session 中。
为了正确实现会话序列化,您需要挂钩序列化事件并在反序列化会话时更新瞬变。 VaadinSession
应该用 VaadinService#loadSession
加载,它调用 VaadinSession#refreshTransients
.
Everything inside a VaadinSession should be serializable to ensure compatibility with schemes using serialization for persisting the session data.
此声明并不意味着您可以开箱即用地序列化您的应用程序。这只是意味着,如果您的应用程序也是可序列化的,那么通过精心设计,您可以序列化整个应用程序。
例如,出于性能原因,Vaadin 不会在每个可能的场合更新会话属性。有方法VaadinService#storeSession
。因此,您需要覆盖正确的方法或设置请求过滤器。例如。你可以在 VaadinService#endRequest
.
请注意,您需要使用粘性会话,以便通过适度的努力使其正常工作。如果您的会话在不同的机器上被反序列化,则可重入锁实例将无效。如果您希望能够在不同的机器上反序列化会话,则需要您的基础设施可以提供您可以使用的分布式锁,而不是 Java 的可重入锁并覆盖 Vaadin 的 getSessionLock
和 setSessionLock
方法来使用它。
进一步信息的宝贵来源:
Vaadin 首席技术官的一般说明
https://vaadin.com/blog/session-replication-in-the-world-of-vaadin
开发人员用一个堆栈完成的推荐
https://vaadin.com/learn/tutorials/hazelcast
另一位高级开发人员的想法