`
m635674608
  • 浏览: 5031560 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

【Spring】Spring Session的简单搭建与源码阅读

 
阅读更多

1. 搭建一个简单的Spring Session例子

1.1. 引入依赖包

    <dependencies>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.7.10.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.8.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session</artifactId>
            <version>1.2.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>4.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.0.1</version>
        </dependency>
        <dependency>
            <groupId>biz.paluch.redis</groupId>
            <artifactId>lettuce</artifactId>
            <version>3.5.0.Final</version>
        </dependency>
    </dependencies>

1.2. 注册Spring IoC、Spring Session和一些Servlet

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    id="WebApp_ID" version="2.5">
    <display-name>Spring-Session-Redis</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
                classpath*:spring-session.xml
            </param-value>
    </context-param>

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

    <servlet>
        <description></description>
        <display-name>SessionTestServlet</display-name>
        <servlet-name>SessionTestServlet</servlet-name>
        <servlet-class>com.nicchagil.SessionTestServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>SessionTestServlet</servlet-name>
        <url-pattern>/SessionTestServlet</url-pattern>
    </servlet-mapping>
    
</web-app>

1.3. 最简单的Spring Session的Bean配置

<?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"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd    
    http://www.springframework.org/schema/context   
    http://www.springframework.org/schema/context/spring-context-3.0.xsd 
    http://www.springframework.org/schema/mvc   
    http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">
    
    <context:annotation-config />

    <!-- Jedis连接工厂 -->
    <bean id="jedisConnectionFactory"
        class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="nick-huang.example" />
        <property name="port" value="6379" />
    </bean>

    <bean id="redisHttpSessionConfiguration"
        class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <property name="maxInactiveIntervalInSeconds" value="1800" />
    </bean>

</beans>

1.4. 一个测试的Servlet

package com.nicchagil;

import java.io.IOException;
import java.util.logging.Logger;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * Servlet implementation class SessionTestServlet
 */
public class SessionTestServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    private Logger logger = Logger.getLogger("SessionTestServlet");

    /**
     * Default constructor. 
     */
    public SessionTestServlet() {
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        HttpSession session = request.getSession();
        
        String username = request.getParameter("username");
        if (username != null && username.length() > 0) {
            session.setAttribute("username", username);
        }
        
        response.getWriter().append("Served at: ").append(request.getContextPath()).append(", userName : " + session.getAttribute("username"));
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        doGet(request, response);
    }

}

1.5. 测试

启动,用浏览器访问该Servlet:http://127.0.0.1:8080/SessionTestServlet?username=123,然后不带参数可能获取用户名:http://127.0.0.1:8080/SessionTestServlet

看下Redis,有没有持久化Session:

[root@blog ~]# /opt/redis-3.2.1/src/redis-cli 
127.0.0.1:6379> keys *
1) "spring:session:sessions:expires:5b29c067-a4b1-4d51-98b2-be084703fc78"
2) "spring:session:sessions:5b29c067-a4b1-4d51-98b2-be084703fc78"
3) "spring:session:expirations:1497195000000"

接下来看下实现原理。

2. 委托过滤器代理类,DelegatingFilterProxy

这个类不在Spring Session中,但它是我们上述例子配置的入口。
它是委托过滤器代理类,可以看到它的继承与实现关系:DelegatingFilterProxy -> GenericFilterBean -> Filter,其中GenericFilterBean的init()调用DelegatingFilterProxy的initFilterBean()。

initFilterBean()的作用是获取委托的过滤器,并调用委托过滤器的doFilter(),这个过滤器是springSessionRepositoryFilter

3. Spring Session主要配置类,RedisHttpSessionConfiguration

说到springSessionRepositoryFilter,那么它在哪里实例化的呢?我们先看看RedisHttpSessionConfiguration
RedisHttpSessionConfiguration,这是一个配置类,它注册了一些Spring Session所需的Bean。我们通过以下的xml显式注册一个配置Bean:

    <bean id="redisHttpSessionConfiguration"
        class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration">
        <property name="maxInactiveIntervalInSeconds" value="1800" />
    </bean>

这个类的继承关系是:RedisHttpSessionConfiguration -> SpringHttpSessionConfigurationSpringHttpSessionConfiguration有个方法叫springSessionRepositoryFilter,这里就是注册springSessionRepositoryFilterBean的地方。关于@Configuration、@Bean方式注册Bean,请点击这里

4. Session存储过滤器,SessionRepositoryFilter

它的继承关系是SessionRepositoryFilter -> OncePerRequestFilter -> Filter
OncePerRequestFilter的名字说明了其作用,看doFilter方法可知,它通过request中的一个Attribute判断是否已做过滤,以保证对于每次请求只做一次此过滤逻辑。如果此请求是首次进入此过滤,则调用SessionRepositoryFilter.doFilterInternal

SessionRepositoryFilter.doFilterInternal,将Servlet容器传入的Request和Response包装成自己封装的Request和Response,然后传给下一任Filter,后续的Filter和Servlet都使用Spring Session封装的Request和Response,此Request和Response分别继承HttpServletRequestWrapper、HttpServletResponseWrapper,并作了自己业务的覆盖。

5. HTTP请求包装类,SessionRepositoryRequestWrapper

SessionRepositoryRequestWrapper根据自身业务,覆盖了许多方法,这里不多讨论,简单举例,比如getSession(boolean)

commitSession()

6. Http请求与Session的关系策略,HttpSessionStrategy

HttpSessionStrategy接口定义了几个方法,另外有几个实现类,这里只讨论一部分:

// 从request获取请求的SessionID,比如SessionID有可能放在Cookie或请求头中
String getRequestedSessionId(HttpServletRequest request);

// 当新Session被创建且应通知客户端新SessionID时此方法会被调用。此方法的实现可能为Cookie或响应头设置新SessionID,当然也可以设置其他信息
void onNewSession(Session session, HttpServletRequest request,
        HttpServletResponse response);

// 当Session销毁时且需通知客户端该SessionID不再有效时会调用此方法。此方法的实现可能为从Cookie或响应头移除SessionID。
void onInvalidateSession(HttpServletRequest request, HttpServletResponse response);

6.1. Cookie方式,CookieHttpSessionStrategy

getRequestedSessionId:

onNewSession:

onInvalidateSession:

6.2. HTTP请求头方式,HeaderHttpSessionStrategy

HeaderHttpSessionStrategy相对简单,根据头键值x-auth-token,从请求中读取sessionID,或设置响应头。
值得注意的是,销毁Session时onInvalidateSession设置响应头x-auth-token的值为空。

7. Session持久化,SessionRepository

这是持久化Session的接口,定义有几个方法:

// 创建能被此实现持久化的新Session。S createSession();

// 持久化Sessionvoid save(S session);

// 根据ID查询SessionS getSession(String id);

// 删除Sessionvoid delete(String id);


http://www.cnblogs.com/nick-huang/p/6986824.html
分享到:
评论

相关推荐

    spring-session-data-redis-2.0.4.RELEASE-API文档-中文版.zip

    赠送jar包:spring-session-data-redis-2.0.4.RELEASE.jar; 赠送原API文档:spring-session-data-redis-2.0.4.RELEASE-javadoc.jar; 赠送源代码:spring-session-data-redis-2.0.4.RELEASE-sources.jar; 赠送...

    spring-session-1.2.1 源码

    spring-session-1.2.1 源码spring-session-1.2.1 源码spring-session-1.2.1 源码

    spring session 中源码更改

    在session共享中遇到的坑。自己通过更改源码实现自定义功能

    spring session redis分布式session

    Spring Session是一个开放源码项目,它扩展了Spring MVC,提供了一种统一的方式来管理和存储用户Session。它的核心功能是在多个应用服务器之间共享Session,从而打破了传统Session的单服务器局限性。Spring Session...

    SpringBoot集成Spring Security登录管理 添加 session 共享【完整源码+数据库】

    1. **Redis Session Store**: Spring Boot可以与Redis集成,将session存储在Redis中。这样,所有服务都可以访问同一个session存储,实现session共享。需要配置`HttpSession`监听器以及相应的Redis配置。 2. **JWT...

    38. Spring Boot分布式Session状态保存Redis【从零开始学Spring Boot】

    要实现Spring Boot分布式Session与Redis的整合,我们需要以下几个步骤: 1. **添加依赖**: 首先在`pom.xml`或`build.gradle`文件中添加Spring Session和Redis的依赖。对于Maven,可以添加如下依赖: ```xml ...

    spring源码分析(1-10)

    Spring 源代码分析系列涵盖了多个关键模块,包括事务处理、IoC容器、JDBC、MVC、AOP以及与Hibernate和Acegi安全框架的集成。以下是对这些知识点的详细阐述: 1. **Spring 事务处理**:Spring 提供了声明式事务管理...

    spring session介绍和源代码分享.pptx

    分布式session简介和 spring session 源码 解析 适合想了解分布式 session的基础知识,想从源码层面了解spring session的同学

    nginx+spring-session+redis 实现session共享

    Spring-Session提供了与Redis集成的API,使得session数据的存取操作变得简单。 实现步骤如下: 1. **配置Spring-Session**:在Spring Boot项目中,添加spring-session和spring-session-data-redis依赖,并在配置...

    SpringSession同时支持Cookie和header策略

    本文将深入探讨SpringSession如何支持Cookie和header策略,并解析`CookieHeaderHttpSessionStrategy.java`这个文件中的关键概念和技术细节。 首先,我们来看标题提及的“SpringSession同时支持Cookie和header策略”...

    spring-session简介及实现原理源码分析

    Spring-Session 实现原理源码分析 Spring-Session 是 Spring旗下的一个项目,旨在解决 Session 管理问题。它可以轻松快捷地集成到我们的应用程序中,并提供了多种存储 Session 的方式。下面是 Spring-Session 的...

    spring-orm源码

    通过阅读和理解Spring-ORM的源码,我们可以深入理解Spring如何与ORM(对象关系映射)框架进行交互,以及Spring如何简化数据访问层的开发。 1. **IoC容器与数据源** Spring的核心是IoC(Inversion of Control)容器...

    Spring Boot Redis Session 共享

    你可以下载并运行这些示例,以加深对Spring Boot与Redis Session共享的理解。通过阅读和调试代码,你将能够更直观地了解整个工作流程。 总的来说,Spring Boot结合Redis实现Session共享是一种常见的解决方案,它...

    Spring Boot Redis Session 共享(Ajax 跨域)

    本教程将详细讲解如何在Spring Boot项目中利用Redis来存储和共享Session,并解决Ajax跨域问题。 首先,我们需要理解Spring Boot中的Session管理。默认情况下,Spring Boot使用内存中的HttpSession来存储用户会话...

    Spring源码解析.pdf

    ### Spring源码解析知识点 #### 一、Spring IoC 容器详解 ##### 1. BeanFactory —— 最基础的IoC容器 - **概念**:`BeanFactory` 是Spring框架中最基本的IoC容器,它负责管理Bean的生命周期,包括创建、配置和...

    spring4+redis3+nginx1实现tomcat集群session共享源码

    本文将详细介绍如何使用Spring、Redis和Nginx来实现Tomcat集群中的Session共享,以及提供相关的源码下载。 首先,我们来看Spring框架。Spring是Java开发中最流行的开源框架之一,它提供了丰富的功能和模块,包括...

    spring-beans源码

    Spring支持五种Bean的作用域:单例(Singleton)、原型(Prototype)、请求(Request)、session(Session)和全局会话(Global Session)。不同的作用域决定了Bean的实例化策略和生命周期。 7. **Bean后处理器** ...

    Spring + Struts +Hibernate简单学习源码

    在"Spring + Struts +Hibernate简单学习源码"中,我们可以看到一个综合性的Java Web项目,它利用这三个框架构建了一个功能完整的应用。以下是对这个项目中涉及的知识点的详细解释: 1. **Spring框架**: - **依赖...

    解决Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题

    在配置类源码中,如果开发者没有为Spring Session自定义一个线程池,那么默认情况下会使用SimpleAsyncTaskExecutor作为线程池。SimpleAsyncTaskExecutor线程池的核心特性是每次调用异步方法时都会创建一个新线程,...

Global site tag (gtag.js) - Google Analytics