同一个tomcat下不同app间session共享

最近在做多个项目单次登录的功能。实质:同一个tomcat下不同app间session共享

前期思考:

每个app的session是独立各自拥有的,若多个项目能公用一个session即可以实现在A项目登录后,B项目避免再次登录的情况。

1、tomcat本身提供了session共享的机制,即设置Context标签的crossContext属性为true,这样在多个项目中拿到的session是同一个。但是实际项目是用的shrio做登录,实际拿到的是shrio提供的session,而非tomcat自身的session,tomcat并未为第三方session提供共享机制,所以该方案无法拿到共享session。(shrio提供了多种session,有实现javaEE标准的session也有完全独立的session,实际项目中使用的完全独立的session)

2、找一个公共区存放session,多个app都可以访问该公共区,其实这是最根本思想。

最终方案:

1、利用容器本身的共享环境ServlertContext

同样需要设置tomcat配置文件servlet.xml,crossContext=true

<Host name="localhost"  appBase="webapps"unpackWARs="true" autoDeploy="true">
    <Context path="/a"  debug="9" reloadable="true" crossContext="true"/> 
    <Context path="/b"  debug="9" reloadable="true" crossContext="true"/>
</Host>

这样,可以通过

servletContext.getContext("/a")获取a项目的web上下文

servletContext.getContext("/b");获取b项目的web上下文

具体过程:

1、访问a项目,先通过servletContext.getContext("/b").getAttribute(sessionId)获取session,若session存在且已登录(session中存在该user的信息),说明已在b项目中已登录,则免登录。若session不存在,创建session并存入a项目的上下文,即servletContext.getContext("/a").setAttribute(sessionId,session)。

2、访问b项目的页面,先通过servletContext.getContext("/a").getAttribute(sessionId)获取session,若session存在且已登录(session中存在该user的信息),说明已在a项目中已登录,则免登录。若session不存在,则新创建session存入b项目的上下文,servletContext.getContext("/b").setAttribute(sessionId,session)。

方案二:自行开辟共享内存区存储session(静态变量,保证共享)

通过实现一个单例模式的session上下文,其实就是一静态map<sessionId,Session>。a,b项目每次都从该map创建、读取session,这就保证了a,b项目共用同一份session。但是,由于tomcat类加载机制的存在,每个app中的类是由各自的类加载加载,所以在各app中会产生各自的Class对象(其实这里是每个app的class文件也是各自独立的),最终拿到的session上下文其实是两个不同的单例对象(仅在其自己的app中是单例)。如果能使用同一个类加载器加载该session上下文的class文件,则能保证在不同app中拿到的session上下文都是同一个了。解决方案:将该sessionContext.class打包放到tomcat的公用目录下,该目录下的class文件都由同一个类加载加载,解决。

补充:所有涉及到多个项目公用的对象类都应该打包放到tomcat的公用目录下,不然会在不同项目中拿到各app独立的对象,而非同一个。

注意:session是通过cookie的sessionId值标识的,在项目中需要正确设置cookie共享的域名与路径以保证在访问a,b项目时带上相同cookie,从而保证拿到同一个session。

方案一和方案二都必须将多个项目放到同一个tomcat进程下,session使用同一个JVM的内存共享,如果将应用部署到不同的tomcat下,以上两种方案都不适用了。因为:

方案一:两个tomcat进程无法通过设置crossContext获取ServletContext

方案二:两个tomcat会启两个JVM,两个JVM的内存无法共享

3、使用redis存储共享session

    原理同为找一个公共区存储session,与方案二的区别是该方案是单独启了一个进程存储session,与应用程序通过网络传输session(其实是每次应用程序去redis读取序列化的session后在本地反序列化成一个对象,相当于是新new了一个对象,将session复制到本地,再比较session id),而方案二是在同一个JVM(同进程)直接共享内存。

该方案对多个tomcat上的session共享也适用。

为了使项目更轻量级,公司采用的是方案二。

      

猜你喜欢

转载自blog.csdn.net/xybz1993/article/details/80260696