Akik: : Have you been paying attention?

Making: making

CSDN: Check it out??

Hobby: Americano More Ice!

directory

  • directory
    • Session
    • Problems & pain points
      • How to solve it?
    • Hand-in-hand – Resolve distributed shared sessions
      • Lead to
      • Don’t talk much, practice first

Session

First of all, what is a Session?

  • Storage: Stored on the server.key-valueData structure storage
  • Common scenario: InsertCookieIs used for session persistence
  • Logic:clientThe first visit toserverWill respond with aSession id.clientTemporarily saved to a local directoryCookie, will be used in future visitscookieIn thesessionIdIn theheadersIf no server is found, a new one will be createdSession idResponse to theclient

Problems & pain points

In a distributed cluster, sessions must be shared. Ask why, and I’ll tell you! Of course you don’t ask, I also want to tell you hh🤭🤭

Because we often run into problems like this, cluster load balancing, and when a client accesses a server (is allocated to one of the resource nodes), and for some reason the load balancing mechanism triggers the client to be allocated to another resource node, In this case, the newly allocated resource node does not store the session information of the client. For example, if the client has logged in but does not obtain the session, the user may be forced to log in again.

How to solve it?

This article mainly recommends a spring-Session integration solution. The overall idea is to share sessions in Redis

  • Distributed sharing Session- source code

Hand-in-hand – Resolve distributed shared sessions

Lead to

  • Docker
  • IDEACompile environment

Don’t talk much, practice first

  1. downloadredis(the default islastestVersion 5.0)
$Docker pull redis: 5.0Pulling from library/redis 69692152171A: Already exists a4a46f2fd7e0: Pull complete bCDf6fDDc3BD: Pull complete 1f499504197d: Pull complete 021b18181099: Pull complete 1fb4123902bc: Pull complete Digest: sha256:c2b0f6fe0588f011c7ed7571dd5a13de58cff538e08d100f0a197a71ea35423a Status: Downloaded newer image for redis: 5.0 docker. IO/library/redis: 5.0Copy the code
  1. Run the container
$ docker run -itd --name redis-test -p 6379:6379 redis
169ad20a55ab0a9e1f05ec237bbfe01dcd8011c4b937ff17a500d6b4210f6165
#Check whether Redis has been started
$ docker ps | grep redis169 ad20a55ab redis: 5.0 "docker - entrypoint. S..." 5 hours ago Up 5 hours 0.0.0.0:6379->6379/ TCP redis-testCopy the code
  1. This is apox.xmlDocuments, only the key parts are listed, i.eredisRely on
.<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
    </dependency>.Copy the code
  1. Write arestfulMethod is used to make requests, and the most important thing about this block of code is that@EnableRedisHttpSessionThe source code implementation of this annotation will also be highlighted below
package geektime.spring.web.session;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;

@SpringBootApplication
@RestController# Here's the point@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400*30)
public class SessionDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(SessionDemoApplication.class, args);
	}

	@RequestMapping("/hello")
	public String printSession(HttpSession session, String name) {
		String storedName = (String) session.getAttribute("name");
		if (storedName == null) {
			session.setAttribute("name", name);
			storedName = name;
		}
		return "hello "+ storedName; }}Copy the code

For emphasis, @enableredisHttpSession annotation source code analysis

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
@Documented
/ / note
@Import({RedisHttpSessionConfiguration.class})
@Configuration
// Implement interface annotations
public @interface EnableRedisHttpSession {
    // Sessio default expiration time (30s x 60s=1800s=30min)
    int maxInactiveIntervalInSeconds(a) default 1800;
    // Session default namespace, 'spring: Session'
    String redisNamespace(a) default "spring:session";
    // Refresh the default Redis Session mode, 'ON_SAVE' : the Session is committed to Redis only after the Response is committed
    RedisFlushMode redisFlushMode(a) default RedisFlushMode.ON_SAVE;
    // Clear the default expiration time of Session, 1min
    String cleanupCron(a) default "0 * * * * *";
}
Copy the code

Part of the code above note, RedisHttpSessionConfiguration is the key to realize, we will find it is inherited SpringHttpSessionConfiguration

public class RedisHttpSessionConfiguration 
        extends SpringHttpSessionConfiguration 
            implements BeanClassLoaderAware.EmbeddedValueResolverAware.ImportAware.SchedulingConfigurer {... }Copy the code

We are into SpringHttpSessionConfiguration see its implementation, registered a SessionRepositoryFilter inside

@Configuration
public class SpringHttpSessionConfiguration implements ApplicationContextAware {...@Bean
    public <S extends Session> SessionRepositoryFilter<? extends Session> springSessionRepositoryFilter(SessionRepository<S> sessionRepository) {
        SessionRepositoryFilter<S> sessionRepositoryFilter = new SessionRepositoryFilter(sessionRepository);
        sessionRepositoryFilter.setServletContext(this.servletContext);
        sessionRepositoryFilter.setHttpSessionIdResolver(this.httpSessionIdResolver);
        returnsessionRepositoryFilter; }... }Copy the code

And lacked a sessionRepository parameters, is injected in RedisHttpSessionConfiguration, have implemented the session configuration of the core code

public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration implements BeanClassLoaderAware.EmbeddedValueResolverAware.ImportAware.SchedulingConfigurer {...@Bean
    public RedisOperationsSessionRepository sessionRepository(a) {
        RedisTemplate<Object, Object> redisTemplate = this.createRedisTemplate();
        RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(redisTemplate);
        sessionRepository.setApplicationEventPublisher(this.applicationEventPublisher);
        if (this.defaultRedisSerializer ! =null) {
            sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
        }

        sessionRepository.setDefaultMaxInactiveInterval(this.maxInactiveIntervalInSeconds);
        if (StringUtils.hasText(this.redisNamespace)) {
            sessionRepository.setRedisKeyNamespace(this.redisNamespace);
        }

        sessionRepository.setRedisFlushMode(this.redisFlushMode);
        int database = this.resolveDatabase();
        sessionRepository.setDatabase(database);
        returnsessionRepository; }... }Copy the code
  1. We’ve had a bit of a hiccup, so let’s start ourspringbootAgain, after successconsoleThe following information is displayed
/Library/Java/JavaVirtualMachines/jdk-15.0.1.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=60016:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/lidean/gitee/geektime-spring-family/Chapter 8/session-demo/target/classes:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot-starter-web/2.1.3.RELEASE/spring-boot-starter-web-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot-starter/2.1.3.RELEASE/spring-boot-starter-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot/2.1.3.RELEASE/spring-boot-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.1.3.RELEASE/spring-boot-autoconfigure-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot-starter-logging/2.1.3.RELEASE/spring-boot-starter-logging-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar:/Users/lidean/.m2/repository/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar:/Users/lidean/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.11.2/log4j-to-slf4j-2.11.2.jar:/Users/lidean/.m2/repository/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2.jar:/Users/lidean/.m2/repository/org/slf4j/jul-to-slf4j/1.7.25/jul-to-slf4j-1.7.25.jar:/Users/lidean/.m2/repository/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar:/Users/lidean/.m2/repository/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot-starter-json/2.1.3.RELEASE/spring-boot-starter-json-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8.jar:/Users/lidean/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar:/Users/lidean/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8.jar:/Users/lidean/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8.jar:/Users/lidean/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8.jar:/Users/lidean/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8.jar:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/2.1.3.RELEASE/spring-boot-starter-tomcat-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.jar:/Users/lidean/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/9.0.16/tomcat-embed-el-9.0.16.jar:/Users/lidean/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.16/tomcat-embed-websocket-9.0.16.jar:/Users/lidean/.m2/repository/org/hibernate/validator/hibernate-validator/6.0.14.Final/hibernate-validator-6.0.14.Final.jar:/Users/lidean/.m2/repository/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar:/Users/lidean/.m2/repository/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar:/Users/lidean/.m2/repository/com/fasterxml/classmate/1.4.0/classmate-1.4.0.jar:/Users/lidean/.m2/repository/org/springframework/spring-web/5.1.5.RELEASE/spring-web-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-beans/5.1.5.RELEASE/spring-beans-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-webmvc/5.1.5.RELEASE/spring-webmvc-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-aop/5.1.5.RELEASE/spring-aop-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-context/5.1.5.RELEASE/spring-context-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-expression/5.1.5.RELEASE/spring-expression-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/boot/spring-boot-starter-data-redis/2.1.3.RELEASE/spring-boot-starter-data-redis-2.1.3.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/data/spring-data-redis/2.1.5.RELEASE/spring-data-redis-2.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/data/spring-data-keyvalue/2.1.5.RELEASE/spring-data-keyvalue-2.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/data/spring-data-commons/2.1.5.RELEASE/spring-data-commons-2.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-tx/5.1.5.RELEASE/spring-tx-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-oxm/5.1.5.RELEASE/spring-oxm-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-context-support/5.1.5.RELEASE/spring-context-support-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/lidean/.m2/repository/io/lettuce/lettuce-core/5.1.4.RELEASE/lettuce-core-5.1.4.RELEASE.jar:/Users/lidean/.m2/repository/io/netty/netty-common/4.1.33.Final/netty-common-4.1.33.Final.jar:/Users/lidean/.m2/repository/io/netty/netty-handler/4.1.33.Final/netty-handler-4.1.33.Final.jar:/Users/lidean/.m2/repository/io/netty/netty-buffer/4.1.33.Final/netty-buffer-4.1.33.Final.jar:/Users/lidean/.m2/repository/io/netty/netty-codec/4.1.33.Final/netty-codec-4.1.33.Final.jar:/Users/lidean/.m2/repository/io/netty/netty-transport/4.1.33.Final/netty-transport-4.1.33.Final.jar:/Users/lidean/.m2/repository/io/netty/netty-resolver/4.1.33.Final/netty-resolver-4.1.33.Final.jar:/Users/lidean/.m2/repository/io/projectreactor/reactor-core/3.2.6.RELEASE/reactor-core-3.2.6.RELEASE.jar:/Users/lidean/.m2/repository/org/reactivestreams/reactive-streams/1.0.2/reactive-streams-1.0.2.jar:/Users/lidean/.m2/repository/org/springframework/session/spring-session-core/2.1.4.RELEASE/spring-session-core-2.1.4.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-jcl/5.1.5.RELEASE/spring-jcl-5.1.5.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/session/spring-session-data-redis/2.1.4.RELEASE/spring-session-data-redis-2.1.4.RELEASE.jar:/Users/lidean/.m2/repository/org/springframework/spring-core/5.1.5.RELEASE/spring-core-5.1.5.RELEASE.jar geektime.spring.web.session.SessionDemoApplication

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \ / _ ` | \ \ \ \ \ \ / ___) | | _) | | | | | | | (_ | |))))' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.1.3. RELEASE) the 2021-06-04 10:34:48. 97269-122 the INFO [main] G.S.W eb. Session. SessionDemoApplication: Starting SessionDemoApplication on MacBook-Pro-9.local with PID 97269 (started by lidean in / Users/lidean/gitee/geektime - spring - family/Chapter 8 / session - demo) 10:34:48 2021-06-04. 97269-125 the INFO [main] g.s.web.session.SessionDemoApplication : No active profile set, falling back to default profiles: Default 10:34:49 2021-06-04. 97269-209 the INFO [main] S.D.R.C.R epositoryConfigurationDelegate: Multiple Spring Data modules found, entering strict repository configuration mode! The 2021-06-04 10:34:49. 97269-214 the INFO [main]. S.D.R.C.R epositoryConfigurationDelegate: Bootstrapping Spring Data repository in DEFAULT mode. 2021-06-04 10:34:49.247 INFO 97269 -- [main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 20ms. Found 0 Repository interfaces. 2021-06-04 10:34:50.151 INFO 97269 -- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (HTTP) 10:34:50 2021-06-04. 97269-181 the INFO [main] o.a pache, catalina. Core. StandardService: Starting the service [Tomcat] 2021-06-04 10:34:50. 182 INFO 97269 - [the main] org. Apache. Catalina. Core. StandardEngine: Starting Servlet engine: Apache Tomcat / 9.0.16 10:34:50 2021-06-04. 97269-194 the INFO [main] O.A.C atalina. Core. AprLifecycleListener: The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [/Users/lidean/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Ex Tensions :/usr/lib/java:.] 2021-06-04 10:34:50.720 INFO 97269 -- [main] O.A.C.C.C. [Tomcat].[/] : Initializing Spring Embedded WebApplicationContext 2021-06-04 10:34:50.720 INFO 97269 -- [main] o.s.web.context.ContextLoader : Root WebApplicationContext: Initialization completed in 2477, the 2021-06-04 ms 10:34:51. 578 INFO 97269 - [the main] IO. Lettuce. Core. EpollProvider: Starting with optional epoll library 10:34:51 2021-06-04. 579 INFO 97269 - [the main] IO. Lettuce. Core. KqueueProvider: Starting without Optional kqueue Library 2021-06-04 10:34:51.970 INFO 97269 -- [main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'97269-2021-06-04 10:34:52. 889 INFO [main] S.A.S cheduledAnnotationBeanPostProcessor: No TaskScheduler/ScheduledExecutorService bean found for scheduled processing 10:34:52 2021-06-04. 97269-920 the INFO [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''97269-2021-06-04 10:34:52. 924 INFO [main] G.S.W eb. Session. SessionDemoApplication: Started SessionDemoApplication in 5.234 seconds (JVM running for 5.782) 2021-06-04 10:34:53.851 INFO 97269 -- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'97269-2021-06-04 10:34:53. 851 INFO [nio - 8080 - exec - 1] O.S.W eb. Servlet. The DispatcherServlet: Initializing the servlet'dispatcherServlet'
2021-06-04 10:34:53.861  INFO 97269 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 10 ms
Copy the code
  1. Now for our first visithttp://localhost:8080/hello?name=spring, remember to open itChrome tool, you can see the createdsession

Enter Redis directly to see the stored K-V data, of course, the specific storage of our information format can also be seen

$ docker exec -it redis-test redis-cli
127.0.0.1:6379> keys *
1) "spring:session:expirations:1622794680000"
2) "spring:session:sessions:expires:1f74b429-8695-47b9-9b24-7adde8bd6aec"
3) "spring:session:sessions:1f74b429-8695-47b9-9b24-7adde8bd6aec"
type spring:session:sessions:1f74b429-8695-47b9-9b24-7adde8bd6aec
hash127.0.0.1:6379 > HGETALL spring: session: f74b429 sessions: 1-8695-47 b9-9 b24 adde8bd6aec 1)"sessionAttr:name"
2) "\xac\xed\x00\x05t\x00\x06spring"
3) "creationTime"
4) "\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\x0 0xp\x00\x00\x01y\xd5\xfdO\n"
5) "maxInactiveInterval"
6) "\xac\xed\x00\x05sr\x00\x11java.lang.Integer\x12\xe2\xa0\xa4\xf7\x81\x878\x02\x00\x01I\x00\x05valuexr\x00\x10java.lang.N umber\x86\xac\x95\x1d\x0b\x94\xe0\x8b\x02\x00\x00xp\x00\x00\a\b"
7) "lastAccessedTime"
8) "\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\x0 0xp\x00\x00\x01y\xd5\xff7\x1e"
Copy the code
  1. We try to modify accessurltheRequest parameters, you will find that no matter how the request parameter changes, it will not affect the return result, because the server uses it firstRedisThe cacheSessionData and information

About the realization of the idea is the above content ~

Conclusion: if encounter what question or suggestion, can leave a message comment directly! The author will reply immediately

If you feel small white this article is good or helpful to you, look forward to your one key three even 💫! ❤ ️ ni ~