先写些废话

  新公司项目是有用到redis,之前老公司使用的缓存框架是ehcache.我redis并不熟悉.看过介绍以后知道是个nosql..既然是个数据库,那我想操作方法和jdbc操作关系数据库应该差不多吧..百度了一些例子以后发现确实差不多...比如注入一个spring的template以后使用template就行了. 比如:

  很好理解,使用也蛮简单..就像jdbcTemplate...

  一次偶然的调试,我发现了一个有趣的地方(公司用的是自己的框架,封装了springboot...所以启动默认配置了什么bean,很难看出来...)...

我记得session在tomcat启动服务器的时候好像是XXXSessionFacade..这里却是和Redis相关的一个实现类..然后向这个session存进去的东西再redis里也可以找到.

这说明这个session数据存取都是向redis去操作的.

看来一下maven的POM文件发现公司的项目依赖于srping-session-data-redis这个框架.

Spring整合SpringSession

实验了一下,发现其实spring只要额外配置2个bean就可以集成springsession了.

    <context:annotation-config />
<bean class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
</bean> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
<property name="hostName" value="10.86.87.173" />
<property name="password" value="mesRedis+)" />
</bean>

稍微研究了下发现JedisConnectionFactory这个bean就是配置了Spring怎么通过jedis去连接redis服务器.

RedisHttpSessionConfiguration这个bean是真正和session相关的,它本身类上有注解@Configuration和@EnableScheduling.

@Configuration配合它方法上的@Bean可以配置一些其他的bean,比如SessionRepositoryFilter 就配置了一个bean,对应web.xmlXML里配置的那个filter...

@EnableScheduling这个注解我没用过,估计是要定时做一些事情,比如session过期了要去redis删除数据吧(但是redis好像也有超时删除数据的功能,为啥还要这么做呢..redis和Springsession都是第一次用,不太了解)..

除了上面2个bean,只要在web.xml里配置一个filter就行了.

     <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>

原理

因为第一次用,很多代码都没看过,所以不一定对.我觉得原理是这样的:

1.RedisHttpSessionConfiguration里会配置一个filter

    @Bean
public <S extends ExpiringSession> SessionRepositoryFilter<? extends ExpiringSession> springSessionRepositoryFilter(SessionRepository<S> sessionRepository, ServletContext servletContext) {
SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter<S>(sessionRepository);
sessionRepositoryFilter.setServletContext(servletContext);
if(httpSessionStrategy != null) {
sessionRepositoryFilter.setHttpSessionStrategy(httpSessionStrategy);
}
return sessionRepositoryFilter;
}

注入一个sessionRepository.这个repository其实就是redis的repository.只是哪里生成的我并不知道...

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
request.setAttribute(SESSION_REPOSITORY_ATTR, sessionRepository); SessionRepositoryRequestWrapper wrappedRequest = new SessionRepositoryRequestWrapper(request, response, servletContext);
SessionRepositoryResponseWrapper wrappedResponse = new SessionRepositoryResponseWrapper(wrappedRequest,response); HttpServletRequest strategyRequest = httpSessionStrategy.wrapRequest(wrappedRequest, wrappedResponse);
HttpServletResponse strategyResponse = httpSessionStrategy.wrapResponse(wrappedRequest, wrappedResponse); try {
filterChain.doFilter(strategyRequest, strategyResponse);
} finally {
wrappedRequest.commitSession();
}
}

这个filter会把request和response外面包装一层,就是装饰着模式.当调用request的getSession的时候

        @Override
public HttpSession getSession(boolean create) {
HttpSessionWrapper currentSession = getCurrentSession();
if(currentSession != null) {
return currentSession;
}
String requestedSessionId = getRequestedSessionId();
if(requestedSessionId != null) {
S session = sessionRepository.getSession(requestedSessionId);
if(session != null) {
this.requestedSessionIdValid = true;
currentSession = new HttpSessionWrapper(session, getServletContext());
currentSession.setNew(false);
setCurrentSession(currentSession);
return currentSession;
}
}
if(!create) {
return null;
}
S session = sessionRepository.createSession();
currentSession = new HttpSessionWrapper(session, getServletContext());
setCurrentSession(currentSession);
return currentSession;
}

其实是从sessionRepository里去拿session的.所以我们使用的HttpSession的实现类应该是 HttpSessionWrapper 里面包裹着 RedisSession.

     private RedisSession getSession(String id, boolean allowExpired) {
Map<Object, Object> entries = getSessionBoundHashOperations(id).entries();
if(entries.isEmpty()) {
return null;
}
MapSession loaded = new MapSession();
loaded.setId(id);
for(Map.Entry<Object,Object> entry : entries.entrySet()) {
String key = (String) entry.getKey();
if(CREATION_TIME_ATTR.equals(key)) {
loaded.setCreationTime((Long) entry.getValue());
} else if(MAX_INACTIVE_ATTR.equals(key)) {
loaded.setMaxInactiveIntervalInSeconds((Integer) entry.getValue());
} else if(LAST_ACCESSED_ATTR.equals(key)) {
loaded.setLastAccessedTime((Long) entry.getValue());
} else if(key.startsWith(SESSION_ATTR_PREFIX)) {
loaded.setAttribute(key.substring(SESSION_ATTR_PREFIX.length()), entry.getValue());
}
}
if(!allowExpired && loaded.isExpired()) {
return null;
}
RedisSession result = new RedisSession(loaded);
result.originalLastAccessTime = loaded.getLastAccessedTime() + TimeUnit.SECONDS.toMillis(loaded.getMaxInactiveIntervalInSeconds());
result.setLastAccessedTime(System.currentTimeMillis());
return result;
}
         @Override
public HttpSession getSession(boolean create) {
HttpSessionWrapper currentSession = getCurrentSession();
if(currentSession != null) {
return currentSession;
}
String requestedSessionId = getRequestedSessionId();
if(requestedSessionId != null) {
S session = sessionRepository.getSession(requestedSessionId);
if(session != null) {
this.requestedSessionIdValid = true;
currentSession = new HttpSessionWrapper(session, getServletContext());
currentSession.setNew(false);
setCurrentSession(currentSession);
return currentSession;
}
}
if(!create) {
return null;
}
S session = sessionRepository.createSession();
currentSession = new HttpSessionWrapper(session, getServletContext());
setCurrentSession(currentSession);
return currentSession;
}

最新文章

  1. Java时间的处理
  2. 【服务器防护】WEB防护 - WEBSHELL攻击探测【转载】
  3. C++模板实例化(1)
  4. [React + webpack] hjs-webpack
  5. docker学习笔记5:利用commit命令创建镜像 和 删除本地镜像
  6. C++对文件进行加密解密
  7. 手机自动化测试:appium源码分析之bootstrap七
  8. prometheus alert rules文件格式化
  9. Celery 1
  10. windows下使用svn命令行
  11. fk输入地壳模型容易出错的地方
  12. Flash网页小游戏开发教程
  13. 读jQuery源码释疑笔记
  14. WIN下Git GUI 教程
  15. Solr学习笔记之5、Component(组件)与Handler(处理器)学习
  16. [转]Golang 中使用 JSON 的小技巧
  17. 更改oracle数据库字符集
  18. 32岁白发菜鸟拿2.6万年薪苦熬10年 NBA首秀便惊艳世人 科比书豪纷纷为他点赞
  19. OSG3.2+Qt5.2.1+VS2012+OSGEarth 2.5编译问题记录
  20. VS2013安装及破解教程

热门文章

  1. cordova学习-基础篇
  2. 几种设置UITableView的cell动态高度的方法
  3. 【angularJS】Route路由
  4. minio 安装以及使用
  5. 笔记:服务器压缩方案 来源于 Accept-Encoding: gzip, deflate 问题
  6. C# WinForm页面切换导致闪烁的解决方法(转)
  7. 结合示例说明C++中const和指针结合时怎么理解
  8. ActiveMQ入门之四--ActiveMQ持久化方式
  9. webView放弃capture()截图的替代方法
  10. (转) Docker EE/Docker CE简介与版本规划