Location>code7788 >text

SpringBoot Session Sharing, Configuration Doesn't Work Problem Troubleshooting → You actually poisoned the code!

Popularity:289 ℃/2024-08-05 08:54:49

Happy Moment

It's almost 8 o'clock and the doughnut vendor hasn't shown up yet, so I have to call him.

Big brother said on the phone: I have been selling doughnuts for so many years, never free, since fucking know you, actually let me have the feeling of going to work!

你让我有了上班的感觉

Session Sharing

SpringBoot session sharing configuration, which I'm sure you all know, but for the sake of accountability, I'm going to show you the

  1. Adding Dependencies

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="/POM/4.0.0"
             xmlns:xsi="http:///2001/XMLSchema-instance"
             xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId></groupId>
        <artifactId>spring-boot-session-demo</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <parent>
            <groupId></groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.7.18</version>
        </parent>
    
        <properties>
            <>8</>
            <>8</>
            <>UTF-8</>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId></groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId></groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
            <dependency>
                <groupId></groupId>
                <artifactId>spring-session-data-redis</artifactId>
            </dependency>
        </dependencies>
    </project>
    
  2. Add Configuration

    File Configuration

    spring:
      session:
        store-type: redis
      redis:
        timeout: 3000
        password: 123456
        host: 10.5.108.226
        port: 6379
    

    annotation configuration

    @SpringBootApplication
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 900, redisNamespace = "session-demo")
    public class SessionApplication {
    
        public static void main(String[] args) {
            (, args);
        }
    }
    

    Two configuration items need to be clarified

    maxInactiveIntervalInSeconds: the effective duration of the session, in seconds, in the example, the effective duration of the session is 900s.

    redisNamespace: redis namespace, i.e. session information will be stored in redis under which namespace, no will be created, the example is session-demo

  3. Operation session

    For simplicity, it is straightforward to provide the interface to set up and access session

    @RestController
    @RequestMapping("hello")
    public class HelloController {
        @GetMapping("/set")
        public String set(HttpSession session) {
            ("user", "qsl");
            return "qsl";
        }
        @GetMapping("/get")
        public String get(HttpSession session) {
            return ("user") + "";
        }
    }
    

At this point, the build is complete, and after startup, visit the

http://localhost:8080/hello/set

And then go to redis and look at the session information.

redis_session

Why is the effective length of time870 rather than900Please stick your head up and I'll whisper it to you.

20230115143049

I'm just asking you guys.SpringBoot Session Share is not very simple? But it is so simple content, even someone to the poison, and I am very unfortunate to become the poisoned person, if I do not have a trick, maybe on the Karma past, the specific details and listen to me slowly say!

Configuration does not take effect

In the actual project, I also configured it as above, but the storage content in redis is

异现象

From the results, the session is indeed shared, but why does themaxInactiveIntervalInSecondsredisNamespace None of the configurations are taking effect? I also made a point of comparing another project with the same configuration process, and that project'snamespace (computing) cap (a poem)active time All of them are working properly, but this program is not working, which makes me completely confused

懵

debug source code

I've tried everything I'm supposed to try.maxInactiveIntervalInSecondsredisNamespace It's not working. There's no way out. We'll have to go for the jugular.

debug debugging source code

Here's the question again: where does the breakpoint hit? There are two places where you need breakpoints

  1. RedisHttpSessionConfiguration#sessionRepository

    Follow-up to@EnableRedisHttpSession Inside the annotation, you will see the@Import()Follow-upRedisHttpSessionConfigurationYou'll see that it's being@Bean modifiedsessionRepository methodology, the normalSpringBoot This method is called during the startup process, so let's make a breakpoint in the first line of the method

    sessionRepository 断点
  2. SpringHttpSessionConfiguration#springSessionRepositoryFilter

    watch carefullyRedisHttpSessionConfiguration The full definition of

    @Configuration(proxyBeanMethods = false)
    public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
    		implements BeanClassLoaderAware, EmbeddedValueResolverAware, ImportAware
    

    It inheritsSpringHttpSessionConfigurationIf you follow me in, you'll find that there's a man who's been@Bean modifiedspringSessionRepositoryFilter methodology, the normalSpringBoot This method is also called during startup, and we also make a breakpoint in the first line of this method

    springSessionRepositoryFilter 断点

After hitting the breakpoint, revert to thedebug way to boot, we will find that the first thing that comes to thespringSessionRepositoryFilter breakpoints

springSessionRepositoryFilter 断点进入

Then we pressF9It will be found that the project was started and finished without coming to theRedisHttpSessionConfiguration#sessionRepository breakpoints, why is this?SpringHttpSessionConfiguration#springSessionRepositoryFilter method has a parameterSessionRepository<S> sessionRepositoryIt relies onRedisIndexedSessionRepository instance, that is, theRedisHttpSessionConfiguration#sessionRepository should be called first.sessionRepository None of the methods are called, thatspringSessionRepositoryFilter What the heck is a parameter instance of a method? Once again, let's take thedebug manner of activation

springSessionRepositoryFilter 参数

What's going on?RedisOperationsSessionRepositoryWhy not?RedisIndexedSessionRepository ? - Yes, sir. Let's find out.RedisOperationsSessionRepository

RedisOperationsSessionRepository

It inherits theRedisIndexedSessionRepositoryThe point is that it was@Deprecated How can an instance of this type be created, and where is it instantiated? Press and hold thectrl key, left mouse clickRedisOperationsSessionRepository

RedisOperationsSessionRepository 被调用

tap intoRedisConfig startled at first glance

RedisOperationsSessionRepository 实例化

A quick look at the submission history reveals2021-09-26 Submitted, took a look at the author, and good lord, he left a long time ago!

代码里下毒

I reckon, when I wanted to do session sharing, but the development was halfway through, and I left directly, you said you left just leave, why did you submit this half of the code, really, angry with my teeth!

comment outRedisConfig After rebooting, everything is back to normal.maxInactiveIntervalInSecondsredisNamespace All normal effect; the actual work of the development, the matter is finished, do not go to the details of the buckle, unless you really idle egg pain. But then again, you all come to read the blog, that is indeed idle, since you are so idle, then we continue to buckle a buckle, buckle what?

Why is the RedisHttpSessionConfiguration#sessionRepository method not called after we specify RedisOperationsSessionRepository and maxInactiveIntervalInSeconds, redisNamespace does not take effect

  1. RedisHttpSessionConfiguration#sessionRepository Why isn't it being called?

    Whether it's our customizedRedisConfig#redisOperationsSessionRepositoryor SpringBoot'sRedisHttpSessionConfiguration#sessionRepositorywhich are parsed by SpringBoot during the startup process into theBeanDefinitionAs for how it was parsed, that involves the@Configuration The principle of parsing, for those who don't know, can be read first:spring-boot-2.0.3source code chapter - @Configuration、Conditiontogether with@Conditional The scanning of the BeanDefinition is sequential. In addition, the scanning of BeanDefinitions is sequential, see details:Triple checking circular dependencies → Remembering an occasional circular dependency problem on the line

    Returning to our case, thenRedisConfig#redisOperationsSessionRepository aheadRedisHttpSessionConfiguration#sessionRepository Scan into BeanDefinition

    bean定义顺序

    And the bean instantiation that immediately follows is in that order, which is to say that theRedisConfig#redisOperationsSessionRepository will be called first; we'll focus on the name of thesessionRepository on the instantiation process of the bean. Here's an additionaldebug As there are a lot of beans and we are only interested in instantiating one of them, we can use IDEA'sCondition to realize

    idea 条件debug

    and then pressF9It will come directly to thesessionRepository instantiation process, and then after thegetBean(String name) alongdoGetBean

    doGetBeanpng

    supplementarytransformedBeanName Methods to follow up on coming tocanonicalName

    anonialName

    This is the point, everyone look carefully, according to the alias recursively read the main name, return the last main name, is not this logic? However, a new question arises

    There's no such thing as an alias, or a master's name.

    Normally, a bean has only one name, the primary name, and you can use the@Bean If you don't specify a name, the name will be the method name by default, but if you do, the specified name will be used; multiple names are supported, the first one is the main name, and all the following ones are aliases.

    主名别名
    aliasMap

    So, according to the aliassessionRepository I got it.redisOperationsSessionRepository This Lord's name

    sessionRepository被替换OperationsSessionRepository

    calledredisOperationsSessionRepository The bean has already been created and is of typeRedisOperationsSessionRepository, which is taken directly from the container and returned; so theRedisHttpSessionConfiguration#sessionRepository It's not being called. You guys get it?

    Returning to the original question, without annotatingRedisConfigAnd just take out the aliases.sessionRepository

    @Configuration
    public class RedisConfig {
    
    	@Autowired
    	private RedisTemplate redisTemplate;
    
    	@Bean({"redisOperationsSessionRepository"})
    	public RedisOperationsSessionRepository redisOperationsSessionRepository() {
    		return new RedisOperationsSessionRepository(redisTemplate);
    	}
    }
    

    Will the problem be solved?

    summarize

    According to the scanning order, the beanDefinition of RedisConfig#redisOperationsSessionRepository precedes RedisHttpSessionConfiguration#sessionRepository, so when the bean instance is created, the RedisOperationsSessionRepository instance is created first. When a RedisOperationsSessionRepository instance is created, the RedisOperationsSessionRepository instance is created first, and the alias of thesessionRepository is a duplicate of RedisHttpSessionConfiguration#sessionRepository, so instead of calling RedisHttpSessionConfiguration#sessionRepository to create an instance, it returns the already created RedisOperationsSessionRepository instance.

  2. maxInactiveIntervalInSeconds, redisNamespace Why don't they work?

    Everyone, pay attention.RedisConfig

    @Configuration
    public class RedisConfig {
    
    	@Autowired
    	private RedisTemplate redisTemplate;
    
    	@Bean({"redisOperationsSessionRepository", "sessionRepository"})
    	public RedisOperationsSessionRepository redisOperationsSessionRepository() {
    		return new RedisOperationsSessionRepository(redisTemplate);
    	}
    }
    

    How to make maxInactiveIntervalInSeconds, redisNamespace effective?

    Now that the officials have putRedisOperationsSessionRepository It's obsolete, so let's not dwell on it and just not use it!

summarize

  1. SpringBoot Session Sharing configuration is very simple, if you configure the results are not right, do not doubt yourself, it must be someone in the code poisoned!
  2. The bottom of the box (debug source code) is not recommended, but it is indeed a foolproof method, do not require you to be proficient, but must be mastered!
  3. As a developer, must have professionalism, development half of the code should not be submitted, really pit people ah!