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

代码:  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. shell 批量检测远程端口

    [DNyunwei@YZSJHL24-209 li]$ cat port.sh #!/bin/bash # ip=`cat iplist` for i in $ip;do port=`ssh -t $ ...

  2. png

  3. ROS-十步完成ROS-indigo安装

    Ubuntu 版本是14.04.5.(这个版本的ubuntu的内核是V4.4的内核,长期维护到2019年,是14代比较稳定的,反正用这个安装就没有什么依赖的头疼的问题,安装ROS很方便,可以去清华的网 ...

  4. python学习记录20181207

    1.python中函数指针的用法 直接把函数名赋值给变量,不需要加上()和形参 如: def add(num1,num2): return num1+num2 fun = add 2.打印输出列表需要 ...

  5. centos7中设置nginx的systemctl启动方式

    1.建立服务文件 (1)文件路径 vim /usr/lib/systemd/system/nginx.service (2)服务文件内容 [Unit] Description=nginx - high ...

  6. python基础之常用关键字总结

    前言 到python3.6为止,python内置的关键字有33个,比python2.7的版本多了2个.下面总结一下python3的关键字的使用. python内置关键字 解释器在加载上下文的时候,如果 ...

  7. springboot集成mybatis源码分析-mybatis的mapper执行查询时的流程(三)

    例: package com.example.demo.service; import com.example.demo.dao.UserDao; import com.example.demo.do ...

  8. Linux-CentOS 重置root密码

    1. 重启服务器,在读秒的时候按任意键,就会出现如下界面 2.接着按下e就会进入到如下界面. 将光标移动到kernel那一行,然后再一次按‘e’,进入kernel该行的编辑界面 3.这就是kernel ...

  9. Java Web项目漏洞:检测到目标URL存在http host头攻击漏洞解决办法

    检测到目标URL存在http host头攻击漏洞 详细描述 为了方便的获得网站域名,开发人员一般依赖于HTTP Host header.例如,在php里用_SERVER["HTTP_HOST ...

  10. 编码 ASCII, GBK, Unicode+utf-8

    0. 1.参考 网页编码就是那点事 阮一峰 字符编码笔记:ASCII,Unicode 和 UTF-8 2.总结 美国 ASCII 码 发音: /ˈæski/ :128个字符,只占用了一个字节的后面7位 ...