有什么办法在tomcat中的不同应用程序之间共享会话状态?

时间:2009-03-20 12:32:19

标签: java session tomcat java-ee

我们希望将工作应用程序拆分为两个不同的.war文件,以便能够在不影响另一个应用程序的情况下更新一个应用程序。每个webapp将具有不同的UI,不同的用户和不同的部署计划。

最简单的路径似乎是共享相同的会话,因此如果应用A设置session.setAttribute("foo", "bar")应用B将能够看到它。

有没有办法在同一个Tomcat实例中共享两个应用的HttpSession状态?

我们的应用程序运行在专用的Tomcat 5.5上,没有其他应用程序在同一个tomcat实例上运行,因此任何有关会话共享的安全问题都不是问题。我们正在运行多个Tomcat实例,但平衡器正在使用粘性会话。

如果不可能,或者会话共享是一个非常糟糕的主意,请发表评论。

11 个答案:

答案 0 :(得分:26)

你不应该分享HttpSession;但你可以分享其他对象。例如,您可以register an object via JNDI访问所有应用程序中的同一对象(数据库使用此对象进行池连接)。

答案 1 :(得分:23)

需要注意的是,两个网络应用程序将使用不同的类加载器。如果要共享对象,则需要在同一个类加载器中使用相同版本的类(否则您将获得LinkageErrors)。这意味着要么将它们放在由两个Web应用程序共享的类加载器中(例如系统类路径),要么使用序列化来有效地排除和重新构建具有正确版本类的正确类加载器中的对象。

答案 2 :(得分:7)

如果您想使用Spring,那么有一个名为 Spring Session 的项目: https://github.com/spring-projects/spring-session

引用:" HttpSession - 允许在应用程序容器(即Tomcat)中立方式替换HttpSession"

答案 3 :(得分:5)

如果to webapps如此紧密耦合以至于他们需要共享对象,为什么要将它分成两部分呢?即使您在某种程度上独立地管理它们,任何体面的构建管理系统都应该能够创建单个WAR文件以进行部署。

像Aaron这样的解决方案建议使用JNDI,但前提是两个webapp都在同一台服务器上运行。如果这些单元是紧密耦合的,那么无论如何你将在同一台服务器上运行...也许只有一个WAR

如果你真的希望他们独立,我会认真检查两者之间的数据交换。理想情况下,您希望它们仅相互共享相关数据。这些数据可以通过POST(或GET,如果更合适)参数来回传递,您甚至可以考虑使用cookie。

答案 4 :(得分:3)

此博客文章中描述了执行此操作的一种方法:Session sharing in Apache Tomcat

摘要:将emptySessionPath添加到Connector配置,将crossContext添加到Context

答案 5 :(得分:2)

conf/context.xml

<Context sessionCookiePath="/">
  ...
  <Manager className="org.redisson.tomcat.RedissonSessionManager"
               configPath="${catalina.base}/conf/redisson.yml"
               readMode="REDIS" />
</Context>

conf/redisson.yml

singleServerConfig:
  address: "redis://<host>:6379"

雷迪森download

sessionCookiePath="/" 使 Tomcat 对不同的 Web 应用程序使用相同的会话 ID。 RedissonSessionManager 使会话保持在“共享空间”


我无法在共享 context.xml 中使用 org.apache.catalina.session.FileStore PersistentManager 获得预期结果,我在后台过期监视器线程中遇到了会话反序列化问题。它未能对会话进行反序列化,因为它使用的是通用类加载器,而类路径中没有 webapp 可序列化模型。理论上,PersistentManager 可以在 WEB-INF/context.xml 中为每个 Web 应用程序单独配置(以具有适当的类路径),但我未能使其工作。

org.apache.catalina.session.JDBCStore PersistentManage 很有前途,因为它公开了会话的 last_access 列,因此不需要反序列化 session_data,但它节省了 app_name 所有导致相同会话 ID 被写入不同 Web 应用程序的不同行的时间。因此会话数据没有存储在共享位置。

Spring Session 有自己的方式来创建会话 ID。我找不到强制 Spring Session 为不同的 Web 应用程序创建相同会话 ID 的解决方案。

具有核心 tomcat 会话 ID 生成的解决方案(能够为不同的网络应用程序生成相同的会话 ID 和 RedissonSessionManager(使用会话 ID 作为唯一键存储数据并具有自己的过期机制)最终对我有用。 该解决方案与 @SessionScope spring beans 完美配合。

答案 6 :(得分:1)

对于Tomcat 8,我使用以下配置在2个Web应用程序之间共享会话:

conf / context.xml

<Context sessionCookiePath="/">
    <Valve className="org.apache.catalina.valves.PersistentValve"/>
    <Manager className="org.apache.catalina.session.PersistentManager">
        <Store className="org.apache.catalina.session.FileStore" directory="${catalina.base}/temp/sessions"/>
    </Manager>
    ...
</Context>

我两次部署相同的简单Web应用程序 log.war log2.war

/log
/log2

我现在可以登录/log并在/log2中显示用户,这不适用于tomcat的默认配置。

enter image description here

已设置会话值并读取:

HttpSession session=request.getSession();  
session.setAttribute("name",name);

HttpSession session=request.getSession(false);  
String name=(String)session.getAttribute("name");  

我以这个项目为例:https://www.javatpoint.com/servlet-http-session-login-and-logout-example

大多数示例/解决方案使用内存数据库,这需要更多的设置工作:

答案 7 :(得分:0)

您可以通过上下文根获取servlet上下文来完成。

用于检索变量。

request.getSession().getServletContext().getContext("/{applicationContextRoot}").getAttribute(variableName)

用于设置变量:

request.getSession().getServletContext().getContext("/{applicationContextRoot}").setAttribute(variableName,variableValue)

注意:两个应用程序都应该部署在同一台服务器上。

如果您发现任何问题,请告诉我

答案 8 :(得分:0)

我使用python为tomcat开发了session state server

由于这个原因,我不需要更改已经为创建/访问和销毁会话而编写的代码。此外,由于存在处理和存储会话的单独服务器/服务,因此不需要主集群。在这种情况下,没有会话复制(如在tomcat集群中),而是在web耕作之间进行会话共享。

答案 9 :(得分:-1)

您不应该通过高可用性按顺序拆分您的应用。您可以在许多tomcat实例上部署整个应用程序。

答案 10 :(得分:-1)

Tomcat 8: 我不得不这样做:{/ 1}}在conf / context.xml中

有关配置属性here

的更多详细信息

然后设置值(比如@ Qazi&#39;答案):

<Context crossContext="true"  sessionCookiePath="/">

获取值:

ServletContext servletContext =request.getSession().getServletContext().getContext("contextPath")
servletContext.setAttribute(variableName,variableValue)