Solve shared session problems with spring session

Source: Internet
Author: User
Tags sesion

1. Sharing Session Issues

HttpSession are created and managed through a servlet container, like Tomcat/jetty are stored in memory. And if we build a distributed cluster of Web servers and then use LVS or nginx for load balancing, HTTP requests from the same user are likely to be distributed to two different Web sites. So the problem is, how to ensure that different Web sites can share the same session data?


The simplest idea is to save the session data to a unified place outside of memory, such as a database such as Memcached/redis. So again, how do you create and manage HttpSession implementations for the servlet container?
(1) Designing a filter, using Httpservletrequestwrapper, to implement its own getsession () method, take over the task of creating and managing session data. Spring-session is realized by this way of thinking. (2) Use the plugin functionality provided by the servlet container to customize the creation and management policies of the httpsession and replace the default policies by configuration. However, there is a drawback to this approach, which is the need to decouple the code of the servlet container such as Tomcat/jetty. In fact, there are already open source projects, such as Memcached-session-manager, and Tomcat-redis-session-manager. TOMCAT6/TOMCAT7 is only supported for the time being.
2.Spring Session Introduction

Spring session is one of spring's projects, GitHub address: https://github.com/spring-projects/spring-session.

The Spring session provides a set of scenarios for creating and managing servlet httpsession. The Spring session provides the cluster session (Clustered Sessions) feature, which uses an external Redis to store session data to solve the session sharing problem.


Here is a description of the features from the official website:

Features

Spring Session provides the following features:

  • API and implementations for managing a user ' s session
  • HttpSession -allows replacing the HttpSession in an application container (i.e. Tomcat) neutral
    • Clustered Sessions -Spring Session makes it trivial to support Clustered Sessions without being tied to an appli cation container specific solution.
    • multiple Browser Sessions -Spring Session supports managing multiple users ' Sessions in a single Browser Instanc E (i.e. multiple authenticated accounts similar to Google).
    • RESTful APIs -Spring session allows providing session IDs in headers to work with RESTful APIs
  • WebSocket -provides the ability to keep the HttpSession alive when receiving WebSocket messages

3. Correct posture for integrated spring session


Here is an example of the actual debug pass, which contains the following 4 steps:

(1) First step, add maven dependency

Depending on the website Quick Start display, the various types of references are not found in the project Pom.xml. So look at the spring session Project Build.gradle file, actually did not configure dependencies of the project, do I have to find its dependence, too unprofessional?!!

<dependencies>    <dependency>        <groupId>org.springframework.session</groupId>        <artifactId>spring-session</artifactId>        <version>1.0.1.RELEASE</version>    </dependency></dependencies>

Finally after many times carefully study the spring session project source code, saw the Spring-session-data-redis project:


The Build.gradle file is configured with the 3 projects that spring session compilation relies on:

Apply from:java_gradleapply from:maven_gradleapply plugin: ' spring-io ' description = ' aggregator for spring Session and S Pring Data Redis "dependencies {Compile project (': Spring-session ')," org.springframework.data:spring-data-redis:$ Springdataredisversion "," Redis.clients:jedis: $jedisVersion "," org.apache.commons:commons-pool2:$ Commonspoolversion "Springioversions" Io.spring.platform:platform-versions:${springioversion} @properties "}

As a result, the real maven dependency changed to Spring-session-data-redis OK:

<dependency>    <groupId>org.springframework.session</groupId>    <artifactId> Spring-session-data-redis</artifactid>    <version>1.0.1.release</version></dependency >

(2) The second step is to write a configuration class that enables the Redishttpsession feature and registers a redisconnectionfactory with the spring container.

Import Org.springframework.context.annotation.bean;import Org.springframework.data.redis.connection.redisconnectionfactory;import Org.springframework.data.redis.connection.jedis.jedisconnectionfactory;import org.springframework.session.data.redis.config.annotation.web.http.enableredishttpsession;@ Enableredishttpsession (maxinactiveintervalinseconds = 7200) public class Redishttpsessionconfig {    @Bean    Public Redisconnectionfactory ConnectionFactory () {        jedisconnectionfactory connectionfactory = new Jedisconnectionfactory ();        Connectionfactory.setport (6379);        Connectionfactory.sethostname ("10.18.15.190");        return connectionfactory;}    }

(3) Step three, add Redishttpsessionconfig to Webinitializer#getrootconfigclasses () and let the spring container load the Redishttpsessionconfig class. Webinitializer is a custom Abstractannotationconfigdispatcherservletinitializer implementation class that is loaded when the servlet is started (and, of course, with a different loading method, such as the use of scanning @configuration annotation classes and so on).

This class uses Java Configuration instead of Web. XML public   class Webinitializer extends Abstractannotationconfigdispatcherservletinitializer {        @Override    protected class<?>[] Getrootconfigclasses () {        return new Class[]{config1.class, Config2.class, redishttpsessionconfig.class};    } //......}

(4) Fourth, write a Abstracthttpsessionapplicationinitializer implementation class that is used to add springsessionrepositoryfilter to the servlet container.

Import Org.springframework.session.web.context.abstracthttpsessionapplicationinitializer;public Class Springsessioninitializer extends Abstracthttpsessionapplicationinitializer {}


4. Spring Session Principle


(1) In the second step of integration Spring-sesion, a configuration Class Redishttpsessionconfig is written,which contains the annotation @EnableRedisHttpSession, A redisconnectionfactory into the spring container is registered through the @bean annotations.

the @enableredishttpsession annotation introduces the Redishttpsessionconfiguration configuration class through import. The configuration class registers a sessionrepositoryfilterwith the spring container with @bean annotations (Sessionrepositoryfilter's Dependencies: Sessionrepositoryfilter----sessionrepository-----redistemplate--redisconnectionfactory).

Package org.springframework.session.data.redis.config.annotation.web.http; @Configuration @enableschedulingpublic Class Redishttpsessionconfiguration implements Importaware, Beanclassloaderaware {//... @Beanpublic redistemplate <String,ExpiringSession> sessionredistemplate (redisconnectionfactory connectionfactory) {//......return Template;} @Beanpublic redisoperationssessionrepository sessionrepository (redistemplate<string, expiringsession> Sessionredistemplate) {//......return sessionrepository;} @Beanpublic <s extends expiringsession> sessionrepositoryfilter<? Extends Expiringsession> springsessionrepositoryfilter (sessionrepository<s> sessionrepository, ServletContext servletcontext) {//......return sessionrepositoryfilter;} //......}

(2) in the fourth step of integrating Spring-sesion, we have written a Springsessioninitializer class that inherits from Abstracthttpsessionapplicationinitializer. The class does not need to overload or implement any method, it is the role of the servlet container initialization, from the spring container to get a default named Sessionrepositoryfilter Filter Class (not previously registered before the error is not found here), And added to the servlet filter chain.

Package org.springframework.session.web.context;/** * Registers the {@link delegatingfilterproxy} to use the * springsess  Ionrepositoryfilter before any other registered {@link Filter}. * * ... */@Order public abstract class Abstracthttpsessionapplicationinitializer implements Webapplicationinitializer {private static final String Servlet_context_prefix = " Org.springframework.web.servlet.FrameworkServlet.CONTEXT. "; public static final String default_filter_name = "Springsessionrepositoryfilter";//......public void Onstartup ( ServletContext ServletContext) throws Servletexception {Beforesessionrepositoryfilter (ServletContext); Configurationclasses! = null) {Annotationconfigwebapplicationcontext Rootappcontext = new Annotationconfigwebapplicationcontext (); Rootappcontext.register (configurationclasses); Servletcontext.addlistener (New Contextloaderlistener (Rootappcontext));} Insertsessionrepositoryfilter (ServletContext);//Register a Sessionrepositoryfilteraftersessionrepositoryfilter ( Servletcontext);} /** * Registers the springsessionrepositoryfilter * @param servletcontext the {@link servletcontext} */private void Insert Sessionrepositoryfilter (ServletContext servletcontext) {String filtername = default_filter_name;// The default name is Springsessionrepositoryfilterdelegatingfilterproxy springsessionrepositoryfilter = new DelegatingFilterProxy ( FilterName);//The Filter agent looks for springsessionrepositoryfilter from the spring container at initialization time, The sessionrepositoryfilter is then actually used for the dofilter operation String ContextAttribute = Getwebapplicationcontextattribute (); ContextAttribute! = null) {Springsessionrepositoryfilter.setcontextattribute (contextattribute);} Registerfilter (ServletContext, True, FilterName, Springsessionrepositoryfilter);} //......}

Sessionrepositoryfilter is one of the highest-priorityJavax.servlet.Filter, which uses a Sessionrepositoryrequestwrapper class to take over the creation and administration of the HTTP session.

Note that the simplified sample code is given below, which differs from the source code of the Spring-session project.

@Order (sessionrepositoryfilter.default_order) public class Sessionrepositoryfilter implements Filter {public        DoFilter (ServletRequest request, servletresponse response, Filterchain chain) {                HttpServletRequest HttpRequest = ( httpservletrequest) request;                Sessionrepositoryrequestwrapper customrequest =                        new Sessionrepositoryrequestwrapper (httpRequest);                Chain.dofilter (customrequest, response, chain);        }        // ...}


public class Sessionrepositoryrequestwrapper extends Httpservletrequestwrapper {public        Sessionrepositoryrequestwrapper (httpservletrequest original) {                super (original);        }        Public HttpSession getsession () {                return getsession (TRUE);        }        Public HttpSession getsession (Boolean createNew) {                //Create a HttpSession implementation from Spring Session        }< c9/>//methods delegate to the original HttpServletRequest ...}
(3) Well, the remaining question is how to load the following two classes when the servlet container starts. Fortunately, all two of these classes have been implementedWebapplicationinitializer interface, it will be loaded automatically。
    • Webinitializer, which is responsible for loading the configuration class. It inherits from Abstractannotationconfigdispatcherservletinitializer and implements the Webapplicationinitializer interface
    • Springsessioninitializer, the filter class that is responsible for adding Sessionrepositoryfilter . It inherits from Abstracthttpsessionapplicationinitializer and implements the Webapplicationinitializer interface


In the Servlet3.0 specification, the servlet container will automatically scan the Javax.servlet.ServletContainerInitializer implementation class when it starts, and in the implementation class we can customize the classes that need to be loaded. In the Spring-web project, there is a Servletcontainerinitializer implementation class Springservletcontainerinitializer, which is annotated @handlestypes ( Webapplicationinitializer.class), let the servlet container automatically look for all the Webapplicationinitializer implementation classes when the class is started.

Package Org.springframework.web, @HandlesTypes (webapplicationinitializer.class) public class Springservletcontainerinitializer implements Servletcontainerinitializer {/** * Delegate the {@code ServletContext} to Any {@link Webapplicationinitializer} * Implementations present on the application classpath. * * <p>because This class declares @{@code handlestypes (Webapplicationinitializer.class)}, * Servlet 3.0+ container s would automatically scan the classpath for implementations * of Spring ' s {@code Webapplicationinitializer} interface and Provide the set of all * such types to the {@code webappinitializerclasses} parameter of this method. * * <p>if No {@code Webapplicationinitializer} implementations be found on the * classpath, this method is Effectiv Ely a no-op. An info-level log message would be is * issued notifying the user that the {@code Servletcontainerinitializer} have indeed * be En invoked but that no {@code Webapplicationinitializer} implementations were * found. * * &LT;p >assuming that one or more {@code Webapplicationinitializer} types is detected, * They'll be instantiated (and &lt  ;em>sorted</em> if the @{@link * Org.springframework.core.annotation.Order @Order} annotation is present or * the {@link org.springframework.core.Ordered Ordered} interface has been * implemented).  Then the {@link webapplicationinitializer#onstartup (ServletContext)} * method would be invoked on each instance, delegating The {@code ServletContext} such * This instance may register and configure servlets such as Spring's * {@code Dispat Cherservlet}, listeners such as Spring ' s {@code Contextloaderlistener}, * or any other Servlet API componentry such as Fil Ters. * * @param webappinitializerclasses all implementations of * {@link Webapplicationinitializer} found on the application cl Asspath * @param servletcontext The servlet context to be initialized * @see Webapplicationinitializer#onstartup (Servletco ntext) * @see annotationawareordercomparator * * @Overridepublic void Onstartup (set<class<?>> webappinitializerclasses, ServletContext ServletContext) throws servletexception {//...}}


5. How do I view session data in Redis?

(1) The Http session data is stored in a hash structure in Redis.


(2) As you can see, there is also a key= "spring:session:expirations:1431577740000" data, which is stored in the set structure. This value records the time at which all session data should be deleted (that is, when the latest session data expires).
127.0.0.1:6379> keys *) "spring:session:expirations:1431577740000" 2) "Spring:session:sessions: e2cef3ae-c8ea-4346-ba6b-9b3b26eee578 "127.0.0.1:6379> type spring:session:sessions: E2cef3ae-c8ea-4346-ba6b-9b3b26eee578hash127.0.0.1:6379> type Spring:session:expirations:1431577740000set


127.0.0.1:6379> keys) "spring:session:expirations:1431527520000" 2) "spring:session:sessions : 59f3987c-d1e4-44b3-a83a-32079942888b "3)" SPRING:SESSION:SESSIONS:11A69DA6-138B-42BC-9916-60AE78AA55AA "4)" spring:session:sessions:0a51e2c2-4a3b-4986-a754-d886d8a5d42d "5)" spring:session:expirations:1431527460000 " 127.0.0.1:6379> hkeys spring:session:sessions:59f3987c-d1e4-44b3-a83a-32079942888b1) "MaxInactiveInterval" 2) " CreationTime "3)" Lastaccessedtime "4)" Sessionattr:attr1 "127.0.0.1:6379> hget spring:session:sessions : 59f3987c-d1e4-44b3-a83a-32079942888b sessionattr:attr1 "\xac\xed\x00\x05sr\x00\x11java.lang.integer\x12\xe2\xa0 \xa4\xf7\x81\x878\x02\x00\x01i\x00\x05valuexr\x00\x10java.lang.number\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\ x00xp\x00\x00\x00\x03 "127.0.0.1:6379> hget spring:session:sessions:59f3987c-d1e4-44b3-a83a-32079942888b CreationTime "\xac\xed\x00\x05sr\x00\x0ejava.lang.long;\x8b\xe4\x90\xcc\x8f#\xdf\x02\x00\x01j\x00\x05valuexr\ X00\x10java.lang.number\x86\xac\x95\x1D\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\x01mm\x94 (\xec " 

6. Reference Articles


Spring Session 1.01 Reference

Getting Started with spring session

Cluster session sharing mechanism


Solve shared session problems with spring session

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.