该代码只是用来学习原理的,有很多不完善之处。

代码:  git@github.com:sicw/EasySpringSession.git

一. 整体设置

1. 实现Filter,封装新的request请求

2. 在newRequest中重写getSession

3. 在getSession中,从redis获取session,或存储session到redis

二. 过滤器

1. 封装request

2. 执行完过滤器链之后要设置sessionId到cookie

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
if(!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)){
throw new RuntimeException("just supports HTTP requests");
}
//封装新的请求
SessionRepositoryRequestWrapper newRequest = new SessionRepositoryRequestWrapper((HttpServletRequest) request, (HttpServletResponse) response);
try {
chain.doFilter(newRequest, response);
}finally {
//持久化session到redis
//设置sessionId到cookie
newRequest.commitSession();
}
}

三. 封装Request

封装Request的主要目的是重写他的getSession操作。

    public class SessionRepositoryRequestWrapper extends HttpServletRequestWrapper {
private HttpServletRequest httpServletRequest;
private HttpServletResponse httpServletResponse;
private HttpSession currentSession; public SessionRepositoryRequestWrapper(HttpServletRequest request,HttpServletResponse response) {
super(request);
httpServletRequest = request;
httpServletResponse = response;
} /**
* 在servlet中调用getSession会触发该方法
* @return session
*/
@Override
public HttpSession getSession() {
HttpSession session = getRequestedSession();
//没有sessionId或sessionId已过期
if(session == null){
session = sessionRepository.createSession();
}
currentSession = session;
return session;
} /**
* 持久化session
* 设置sessionId到Cookie
*/
public void commitSession(){
HttpSession session = currentSession;
sessionRepository.save(session);
String sessionId = session.getId();
httpSessionIdResolver.setSessionId(httpServletRequest, httpServletResponse, sessionId);
} private HttpSession getRequestedSession() {
//获取sessionId
List<String> sessionIds = httpSessionIdResolver.resolveSessionIds(httpServletRequest);
//获取session
for (String sessionId : sessionIds) {
HttpSession session = sessionRepository.findById(sessionId);
if(session != null){
return session;
}
}
return null;
}
}

四. 持久化session

这里持久化session使用的是spring-data-redis,把session通过HMSEt存储到redis中

    @Override
public RedisSession createSession() {
return new RedisSession();
}
@Override
public void save(HttpSession session) {
((RedisSession)session).saveDelta();
} @Override
public RedisSession findById(String id) {
return getSession(id, false);
} @Override
public void deleteById(String id) {
redisTemplate.delete(id);
}

五. 测试

1. 创建webapp

2. 实现SetServlet和GetServlet

@WebServlet("/get")
public class GetServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String key = req.getParameter("name");
HttpSession session = req.getSession();
String value = (String) session.getAttribute(key);
System.out.println("get ["+key+","+value+"]");
}
}
@WebServlet("/set")
public class SetServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String key = req.getParameter("name");
String value = req.getParameter("value");
HttpSession session = req.getSession();
session.setAttribute(key,value);
System.out.println("set ["+key+","+value+"]");
}
}

配置web.xml
因为我们的Filter需要设置属性,如果直接在这里配置Filter那么不能设置属性了。所以使用委派类DelegatingFilterProxy

他会根据Filter-Name去spring查找相应的bean,我们把Filter配置成bean就可以设置他的属性了。

<web-app>
<display-name>Archetype Created Web Application</display-name> <filter>
<filter-name>springSessionRepositoryFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter> <filter-mapping>
<filter-name>springSessionRepositoryFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- 加载配置文件 -->
<context:property-placeholder location="classpath:redis.properties" /> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
<property name="maxIdle" value="${redis.maxIdle}" />
<property name="maxTotal" value="${redis.maxTotal}" />
<property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
<property name="blockWhenExhausted" value="${redis.blockWhenExhausted}" />
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean> <bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<property name="clusterNodes">
<set>
<bean id="redisNode1" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.host1}"/>
<constructor-arg name="port" value="${redis.port1}"/>
</bean>
<bean id="redisNode2" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.host2}"/>
<constructor-arg name="port" value="${redis.port2}"/>
</bean>
<bean id="redisNode3" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.host3}"/>
<constructor-arg name="port" value="${redis.port3}"/>
</bean>
<bean id="redisNode4" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.host4}"/>
<constructor-arg name="port" value="${redis.port4}"/>
</bean>
<bean id="redisNode5" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.host5}"/>
<constructor-arg name="port" value="${redis.port5}"/>
</bean>
<bean id="redisNode6" class="org.springframework.data.redis.connection.RedisNode">
<constructor-arg name="host" value="${redis.host6}"/>
<constructor-arg name="port" value="${redis.port6}"/>
</bean>
</set>
</property>
</bean> <!-- Spring-redis连接池管理工厂 -->
<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<constructor-arg name="clusterConfig" ref="redisClusterConfiguration"/>
<property name="timeout" value="${redis.timeout}" />
<property name="poolConfig" ref="poolConfig" />
<property name="usePool" value="true"/>
</bean> <!-- redis template definition -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
<property name="connectionFactory" ref="jedisConnectionFactory" />
<property name="keySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
</bean> <bean id="redisSessionRepository" class="com.channelsoft.ccod.session.RedisSessionRepository">
<constructor-arg name="redisTemplate" ref="redisTemplate"/>
</bean>

  <!-- 在这里配置了Filter,并且设置属性 -->
<bean id="springSessionRepositoryFilter" class="com.channelsoft.ccod.filter.SessionRepositoryFilter">
<property name="sessionRepository" ref="redisSessionRepository"/>
</bean>
</beans>

redis.properties配置

#Common Config
redis.password=""
redis.maxIdle=400
redis.maxTotal=6000
redis.maxWaitMillis=1000
redis.blockWhenExhausted=true
redis.testOnBorrow=true
redis.timeout=100000
defaultCacheExpireTime=60 #Cluster Config
redis.host1=10.130.29.83
redis.port1=6379
redis.host2=10.130.29.83
redis.port2=6380
redis.host3=10.130.29.83
redis.port3=6381
redis.host4=10.130.29.83
redis.port4=6382
redis.host5=10.130.29.83
redis.port5=6383
redis.host6=10.130.29.83
redis.port6=6384

最后配置容器端口,比如Tomcat创建两个配置端口分别为8080,8081,启动容器。
通过url访问:
http://localhost:8080/set?name=k1&value=v1

http://localhost:8081/get?name=k1

一个简单的分布式session框架的更多相关文章

  1. 用go和zk实现一个简单的分布式server

    golang的zk客户端 最近打算写个简单的配置中心,考虑到实现便捷性,语言选择了go,由于其中计划用到zk,就调研了下golang的zk客户端,并实现了个简单的分布式server.最终找到了两个,地 ...

  2. 超详细,新手都能看懂 !使用SpringBoot+Dubbo 搭建一个简单的分布式服务

    来自:JavaGuide Github 地址:https://github.com/Snailclimb/springboot-integration-examples 目录: 使用 SpringBo ...

  3. Node.js简单介绍并实现一个简单的Web MVC框架

    编号:1018时间:2016年6月13日16:06:41功能:Node.js简单介绍并实现一个简单的Web MVC框架URL :https://cnodejs.org/topic/4f16442cca ...

  4. ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁

    作者:Grey 原文地址: ZooKeeper学习笔记四:使用ZooKeeper实现一个简单的分布式锁 前置知识 完成ZooKeeper集群搭建以及熟悉ZooKeeperAPI基本使用 需求 当多个进 ...

  5. Tornado自定义分布式session框架

    一.session框架处理请求执行的流程: 1.服务器端生成随机的cookie字符串 2.浏览器发送请求,服务器将cookie返回给浏览器. 3.服务器在生成一个字典.字典的key为cookie,va ...

  6. 从零构建一个简单的 Python Web框架

    为什么你想要自己构建一个 web 框架呢?我想,原因有以下几点: 你有一个新奇的想法,觉得将会取代其他的框架 你想要获得一些名气 你遇到的问题很独特,以至于现有的框架不太合适 你对 web 框架是如何 ...

  7. Directx11学习笔记【十一】 画一个简单的三角形--effect框架的使用

    这里不再介绍effect框架的具体使用,有关effect框架使用可参考http://www.cnblogs.com/zhangbaochong/p/5475961.html 实现的功能依然是画一个简单 ...

  8. 一个简单的通讯服务框架(大家发表意见一起研究)JAVA版本

    最近研究下java语言,根据一般使用的情况,写了个连接通讯服务的框架: 框架结构 C-Manager-S; 把所有通讯内容抽取成三个方法接口:GetData,SetData,带返还的Get; 所有数据 ...

  9. 一个简单的CPP处理框架

    好久没有在csdn上写过东西了,这么多年,一方面是工作忙,下班到家也没有开过电脑了,要陪小孩玩: 下面分享一段代码,是用CPP做的一个简单的消息(协议)处理框架: 是通过成员函数指针+map来实现的: ...

随机推荐

  1. java(10)类的无参方法

    一.变量的作用域(有效的使用范围) 1.变量有2种 1.1成员变量(属性) 声明在类的里面,方法的外面 1.2 局部变量 声明在方法里面或for循环结构中 2.调用时的注意事项(初始值不同.作用域不同 ...

  2. 边框回归(bounding-Box regression)

    转自:https://blog.csdn.net/zijin0802034/article/details/77685438 为什么要边框回归? 什么是边框回归? 边框回归怎么做的? 边框回归为什么宽 ...

  3. UE4 AR开发笔记

    1.基础使用 ArToolKit:生成图片特征,可以用彩图.(图片先灰化)    genTexData效准相机.由于有的相机照相有弧度.  calib_camera 2.使用UE4ARPlugins做 ...

  4. Pytorch中的自动求导函数backward()所需参数含义

    摘要:一个神经网络有N个样本,经过这个网络把N个样本分为M类,那么此时backward参数的维度应该是[N X M] 正常来说backward()函数是要传入参数的,一直没弄明白backward需要传 ...

  5. C语言之路-3-循环

    1.while循环计算数字位数 #include<stdio.h> int main() { ; int x; printf("请输入数字:"); scanf(&quo ...

  6. 游记-WC2019

    Day0 报道.开幕式 一大早起来吃了个老北京炸酱面,然而一点都不北京,发现店子墙壁上"这9是--"(cy语) 一路辗转到了二中,报到时在签字版爷稳稳名字下写了cgz ak ioi ...

  7. 全平台网页播放器兼容H5与Flash还带播放列表

    许久不发文了,2018年第一篇文章,写点干货--关于网页播放器的问题.嗯,实际上我是在52破解首发的,当做新人贴. 目前来说,网页播放器不少,随便找找都能找到一大堆,然而好用的就那么几个,比如ckpl ...

  8. 【MySql】常用方法总结

    将一个字段分组,统计每组重复个数,并排序 SELECT Customer, OrderDate, count(*) as Num FROM `all_orders` GROUP BY Customer ...

  9. Hdu 1022 Train Problem I 栈

    Train Problem I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  10. 分享腾讯云的Linux服务器连接速度很慢的解决心得(原创)

    最近发觉连接服务器非常慢,之前没有出现过这种情况. 我在这个腾讯云的服务器上弄了很多虚拟服务器,估计是数据量太大 造成了冗余数据较多的原因,咨询了下腾讯云的小哥, 给我了个明确的回复: 您反馈Xshe ...