Spring-session implementation principle of Session sharing and source analysis

Source: Internet
Author: User
Tags session id server memory redis server



Know it, but also know why.






This article describes the principle of the entire implementation of spring-session. And the core of the source code for a simple introduction. Introduction to the principle of realization






Implementation principle here is a brief description:






When the Web server receives the HTTP request, and when the request enters the corresponding filter, the process that originally needs to be created by the Web server is forwarded to spring-session for creation, and the session that was created is saved in the Web server memory. Session information created through Spring-session can hold third-party services, such as Redis,mysql. Web servers share data by connecting to Third-party services to achieve session sharing.






the entire implementation process and source code detailed introduction






This source is based on the previous content, and in the save session will only analyze the use of jedisconnectionfactory implementation of the redisconnectionfactory. 1.SessionRepositoryFilter and jedisconnectionfactory registration process






Process:












Description


1. When starting a Web project, read Web.xml, read order Content-param--> Listener--> filter--> servlet


2. The role of the Contextloaderlistener listener is to automatically assemble the ApplicationContext configuration information


3 and initialize the root Web application context when the Web container is started.


4, springhttpsessionconfiguration registration Springsessionrepositoryfilter:bean,redishttpsessionconfiguration Registration Sessionredistemplate:bean and Sessionrepository:bean


5, configuration file configuration Jedisconnectionfactory implements Redisconnectionfactory, creating a jedisconnectionfactory bean




Code analysis is as follows: Web.xml, loading the XML configuration file and initializing the Web application context




 <context-param>

   <param-name>contextConfigLocation</param-name>

   <param-value> classpath*:spring/*xml</param-value>

 </context-param>



 <listener>

   < Listener-class>org.springframework.web.context.contextloaderlistener</listener-class>

 </ Listener>




In 2.application-session.xml, the Bean,web application of the redishttpsessionconfiguration bean and Jedisconnectionfactory is configured to initialize the load bean.




<!--Create a spring bean name Springsessionrepositoryfilter implementation filter.


  the filter is responsible for replacing the HttpSession implementation with spring session support. In this instance, the spring session is supported by Redis. -->


  <bean class= " Org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration "/>




  < !--creates a redisconnectionfactory that connects the spring session to the Redis server. We configure the local host connected to the default port (6379). -->


  <!--cluster redis-->


  <bean id= "jedisconnectionfactory" class= " Org.springframework.data.redis.connection.jedis.JedisConnectionFactory ">


      <!--redis-cluster-->


      <constructor-arg index= "0" ref= "redisclusterconfig"/>




      <!--Configure the Redis connection pool, you can not configure, use the default on the line. -->


      <constructor-arg index= "1" ref= "Jedispoolconfig"/>


  </bean>




Contextloaderlistener

   /**

    * Initializes the root Web application context.

    *

   /@Override public

   void contextinitialized (Servletcontextevent event) {

       Initwebapplicationcontext (Event.getservletcontext ());

   }




4.RedisHttpSessionConfiguration class Diagram













Redishttpsessionconfiguration inherited Springhttpsessionconfiguration.




public class Redishttpsessionconfiguration extends Springhttpsessionconfiguration

       implements Embeddedvalueresolveraware, Importaware {




4.1 springhttpsessionconfiguration to create a bean named Springsessionrepositoryfilter




@Bean public


  <s extends expiringsession> sessionrepositoryfilter< extends expiringsession> Springsessionrepositoryfilter (


          sessionrepository<s> sessionrepository) {


      sessionrepositoryfilter <S> sessionrepositoryfilter = new sessionrepositoryfilter<s> (


              sessionrepository);


      Sessionrepositoryfilter.setservletcontext (this.servletcontext);


      if (this.httpsessionstrategy instanceof multihttpsessionstrategy) {


          Sessionrepositoryfilter.sethttpsessionstrategy (


                  (multihttpsessionstrategy) this.httpsessionstrategy);


      }


      else {


          sessionrepositoryfilter.sethttpsessionstrategy (this.httpsessionstrategy);


      }


      return sessionrepositoryfilter;


  }







4.2 Create a redishttpsessionconfiguration#redistemplate bean with the name Sessionredistemplate




@Bean public


  Redistemplate<object, object> sessionredistemplate (


          redisconnectionfactory ConnectionFactory) {


          //instantiate redistemplate


      redistemplate<object, object> template = new redistemplate< Object, object> ();


      Sets the key serialization Stringredisserializer


      Template.setkeyserializer (New Stringredisserializer ());


      Set the hash key  Stringredisserializer


      Template.sethashkeyserializer (New Stringredisserializer ());


      if (This.defaultredisserializer!= null) {


          template.setdefaultserializer (this.defaultredisserializer);


      }


      Set ConnectionFactory. The fifth step is created (the actual connectionfactory loading process is not the same as the process sequence)


      template.setconnectionfactory (connectionfactory);


      return template;


  }




4.3 Create a redishttpsessionconfiguration#redisoperationssessionrepository bean with the name Sessionrepository




@ Bean


Public RedisOperationsSessionRepository sessionRepository (


// use the sessionRedisTemplate bean


@ the Qualifier (" sessionRedisTemplate ") RedisOperations < Object, the Object > sessionRedisTemplate,


ApplicationEventPublisher ApplicationEventPublisher) {




/ / instantiate RedisOperationsSessionRepository


RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository (


SessionRedisTemplate);


/ / set applicationEventPublisher


SessionRepository. SetApplicationEventPublisher (applicationEventPublisher);


/ / set the maximum expiry time maxInactiveIntervalInSeconds = 1800


sessionRepository


SetDefaultMaxInactiveInterval (enclosing maxInactiveIntervalInSeconds);


If (this. DefaultRedisSerializer! = null) {


SessionRepository. SetDefaultSerializer (enclosing defaultRedisSerializer);


}




String redisNamespace = getRedisNamespace ();


If (StringUtils. HasText (redisNamespace)) {


SessionRepository. SetRedisKeyNamespace (redisNamespace);


}




SessionRepository. SetRedisFlushMode (enclosing redisFlushMode);


Return sessionRepository;


}




Create Redisconnectionfactory Bean as Jedisconnectionfactory

<bean id= "Jedisconnectionfactory" class= " Org.springframework.data.redis.connection.jedis.JedisConnectionFactory ">


2.SessionRepositoryFilter added to Filterchain



Process:












Description




1 2, in the Servlet3.0 specification, the servlet container launches automatically scans the Javax.servlet.ServletContainerInitializer implementation class, in which we can customize the classes that need to be loaded. The annotation @handlestypes (Webapplicationinitializer.class) allows the servlet container to automatically look for all Webapplicationinitializer implementation classes when the class is started.


2.1, the Insertsessionrepositoryfilter method obtains the Sessionrepositoryfilter through the FilterName, and creates the new Delegatingfilterproxy ( FilterName);


3 4, then add filter to Filterchain





1.ServletContainerInitializer implementation class loading and implementation of class loading via annotation @handlestypes (webapplicationinitializer.class)




Load implementation class

@HandlesTypes (Webapplicationinitializer.class)

// Springservletcontainerinitializer implementation Servletcontainerinitializer Public

class Springservletcontainerinitializer implements Servletcontainerinitializer {


//------------





2.AbstractHttpSessionApplicationInitializer implementation Webapplicationinitializer for loading




@Order public

Abstract class Abstracthttpsessionapplicationinitializer

       implements Webapplicationinitializer {




2.1 Onstartup




public void Onstartup (ServletContext servletcontext) throws Servletexception {

       Beforesessionrepositoryfilter ( ServletContext);

       if (this.configurationclasses!= null) {

           Annotationconfigwebapplicationcontext rootappcontext = new Annotationconfigwebapplicationcontext ();

           Rootappcontext.register (this.configurationclasses);

           Servletcontext.addlistener (New Contextloaderlistener (Rootappcontext));

       }

       Add Filter

       insertsessionrepositoryfilter (ServletContext);

       Aftersessionrepositoryfilter (ServletContext);

   }




2.1.1.insertSessionRepositoryFilter




   /**

    * Registered springsessionrepositoryfilter

    * @param servletcontext the {@link servletcontext} * *

   Private void Insertsessionrepositoryfilter (ServletContext servletcontext) {

//Default_filter_name = " Springsessionrepositoryfilter "

       String filtername = default_filter_name;

Create Delegatingfilterproxy delegatingfilterproxy through filtername

       springsessionrepositoryfilter = new Delegatingfilterproxy (

               filtername);

       String ContextAttribute = Getwebapplicationcontextattribute ();

       if (ContextAttribute!= null) {

           springsessionrepositoryfilter.setcontextattribute (contextattribute);

       }

Add filter to Filterchain

       registerfilter (ServletContext, True, FilterName, based on filtername and context) Springsessionrepositoryfilter);

   }


Registerfilter

   private void Registerfilter (ServletContext ServletContext,

           boolean insertbeforeotherfilters, String filtername, Filter Filter {

       Dynamic registration = Servletcontext.addfilter (filtername, filter);

       if (registration = = NULL) {

           throw new IllegalStateException (

                   "Duplicate Filter registration for" + Filtername+ "'. Check to ensure the ' Filter is ' only configured once. ');

       }

       Whether asynchronous is supported, default True

       registration.setasyncsupported (isasyncsessionsupported ());

       Get Dispatchertype springsessionrepositoryfilter

       enumset<dispatchertype> dispatchertypes = Getsessiondispatchertypes ();

       Adds a filter map with the given URL pattern and the dispatcher type of the filter represented by this filterregistration. Filter mappings are matched in the order in which they are added.

       registration.addmappingforurlpatterns (Dispatchertypes,!insertbeforeotherfilters,

               "/*");

   }


AddFilter Add filter to ServletContext

   Public filterregistration.dynamic addfilter (

       String FilterName, filter filter);


3.SessionRepositoryFilter interception Process



Process:












Description




1, request is delegatingfilterproxy: intercept to, and then execute the Dofilter method, in Dofilter find the execution of the proxy class.

2. Onceperrequestfilter: Agent Filter Executes Dofilter method, then calls abstract method Dofilterinternal

3, Sessionrepositoryfilter Inherits the Onceperrequestfilter, implements the Dofilterinternal, this method encapsulates a Wrappedrequest, saves session information by executing commitsession to Redis




1 request came in, intercepted by Delegatingfilterproxy, configured in Web.xml

1.1 Executive Dofilter




If you do not specify a destination bean name, use the filter name.

           @Override public void Dofilter (ServletRequest request, servletresponse response, Filterchain Filterchain) Throws Servletexception, IOException {//if required, delay initialization of delegates.

       necessary.

       Filter delegatetouse = this.delegate; if (Delegatetouse = = null) {synchronized (this.delegatemonitor) {if (this.delegate = = null)

                   {Webapplicationcontext WAC = Findwebapplicationcontext ();

                               if (WAC = = null) {throw new IllegalStateException ("No Webapplicationcontext found:" +

                   "No Contextloaderlistener or Dispatcherservlet registered");

               } this.delegate = Initdelegate (WAC);

           } delegatetouse = This.delegate;

   }//Let the delegate perform the actual dofilter operation Invokedelegate (Delegatetouse, request, response, Filterchain); }



1.2 Initdelegate




Protected Filter initdelegate (Webapplicationcontext WAC) throws Servletexception {

// You can get to sessionrepositoryfilter [remark 1]

       Filter delegate = Wac.getbean (Gettargetbeanname (), filter.class);

       if (Istargetfilterlifecycle ()) {

           delegate.init (Getfilterconfig ());

       }

       return delegate;

   }


[Note 1] because: Sessionrepositoryfilter is one of the highest priority Javax.servlet.Filter

/* @Order ( Sessionrepositoryfilter.default_order) Public

class Sessionrepositoryfilter<s extends expiringsession>

       extends Onceperrequestfilter {


* * *


Delegate.dofilter ();

   protected void Invokedelegate (

           Filter delegate, ServletRequest request, servletresponse response, Filterchain Filterchain)

           throws Servletexception, IOException {

       //Agent to execute Dofilter, agent for Sessionrepositoryfilter

       Delegate.dofilter (Request, response, filterchain);

   }





2.1 Onceperrequestfilter#dofilter




Public final void Dofilter (ServletRequest request, servletresponse response, Filterchain Filterchain) throws S Ervletexception, IOException {if (!) ( Request instanceof HttpServletRequest) | | ! (Response instanceof HttpServletResponse))

       {throw new Servletexception ("Onceperrequestfilter just supports HTTP requests");

       } httpservletrequest HttpRequest = (httpservletrequest) request;

       HttpServletResponse HttpResponse = (httpservletresponse) response;


       Boolean hasalreadyfilteredattribute = Request. getattribute (this.alreadyfilteredattributename)!= null; if (Hasalreadyfilteredattribute) {//without calling this filter ... filterchain.dofilter (Request, Respon

       SE); else {//call this filter ... request.setattribute (This.alreadyfilteredattributename, Boolean.true)

           ;

               Try {//dofilterinternal is an abstract methodDofilterinternal (HttpRequest, HttpResponse, Filterchain);

               Finally {//delete "filtered" Request properties for this request.)

           Request.removeattribute (This.alreadyfilteredattributename);

}

       }

   }

Execute sessionrepositoryfilter#dofilterinternal

@Override protected void dofilterinternal (HttpServletRequest request, httpservletresponse response, Filter Chain Filterchain) throws Servletexception, IOException {request.setattribute (session_repository_attr

       , this.sessionrepository); Create a sessionrepositoryrequestwrapper using HttpServletRequest, HttpServletResponse, and ServletContext SessionRepositoryR Equestwrapper wrappedrequest = new Sessionrepositoryrequestwrapper (request, Response, This.servletcontext

       ); Sessionrepositoryresponsewrapper wrappedresponse = new Sessionrepositoryresponsewrapper (WrappedRequest, R


Esponse); Use Cookiehttpsessionstrategy to repackage httpservletrequest httpservletrequest strategyrequest = This.httpSessionStrateg

       Y. Wraprequest (Wrappedrequest, wrappedresponse); HttpServletResponse strategyresponse = this.httpsessionstrategy. Wrapresponse (Wrappedrequest, WrappedRespo


       NSE); TrY {//Execute other filter filterchain.dofilter (Strategyrequest, strategyresponse);

       Finally {//Save session Information Wrappedrequest.commitsession ();

}

   }



4. Wrappedrequest.commitsession () Look at the fourth big Point analysis 4.SessionRepository save session data






Process:






Description




1, submit session Save

2, get the current session, this step is more important, get a httpsessionwrapper, this httpsessionwrapper replaced HttpSession

3, Wrappedsession gets the current session

4, saves session content using Redistemplate, and invokes Redisconnection Use its implementation class jedisclusterconnection to get Redis connections




1.commitSession




/**

* Writes the session ID to the response using Httpsessionstrategy. * Save session.

* *

private void Commitsession () {

           Httpsessionwrapper wrappedsession = getcurrentsession ();

           if (wrappedsession = = null) {

               if (isinvalidateclientsession ()) {

                   SessionRepositoryFilter.this.httpSessionStrategy

                           . Oninvalidatesession (this, this.response);

               }

           }

           else {

               S session = Wrappedsession.getsession ();

               SessionRepositoryFilter.this.sessionRepository.save (session);

               if (!isrequestedsessionidvalid ()

                       | | |!session.getid (). Equals (Getrequestedsessionid ())) {

                   SessionRepositoryFilter.this.httpSessionStrategy.onNewSession (Session, this

                           , this.response);}}

       




2.getCurrentSession




Session Repository Request property name.


public static final String session_repository_attr = Sessionrepository.class. GetName (); private static final String current_session_attr = session_repository_attr + ".


Current_session ";

           Private Httpsessionwrapper getcurrentsession () {return (Httpsessionwrapper)//Get session

       GetAttribute (CURRENT_SESSION_ATTR);

    /** * The default behavior of this method is to invoke GetAttribute (string name) on the wrapper request object.

   */Public Object getattribute (String name) {///The request here is the return This.request.getAttribute (name) encapsulated above; }<




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.