Spring Session plus Redis (Shandong Shumanjianghu)

redis-spring-boot

Session is a very common concept. The role of the session is to assist the http protocol, because http itself is a stateless protocol. In order to record the user's state, the session mechanism came into being. At the same time, session is also a very old concept, and there are many ways to use session. As far as Java is concerned, the servlet standard itself includes session, Tomcat will store the session information in the server memory, and Request provides a method to obtain the session.

However, the session mechanism described above actually has many shortcomings. The first is that the session data does not have a certain persistence mechanism, and it is difficult to achieve horizontal expansion of the application server. In the load balancer + application server cluster architecture, session sharing is a basic requirement. In the Spring ecosystem, Spring session also has the function of storing and sharing sessions. Spring Session supports storing session information in various forms, such as database or Redis. Personally, Redis is more suitable for storing session data than RDBMS. First of all, session data is time-sensitive, and the data timeout mechanism of Redis can complete the clearing of session information. In addition, the data access speed of Redis is faster, and for session data with strong timeliness, there will be better acceleration effect.

Due to the existence of annotations, adding Spring Session Redis to a Spring project is very simple:

1. Increase the dependencies of Spring Session and Spring Data Redis

    compile 'org.springframework.session:spring-session:1.3.0.RELEASE'

    compile 'org.springframework.boot:spring-boot-starter-data-redis'

2. Increase the configuration of Spring Session Redis

@EnableRedisHttpSession
public class HttpSessionConfig {
    @Bean
    public RedisConnectionFactory connectionFactory() {
        JedisConnectionFactory connectionFactory = new JedisConnectionFactory();
        connectionFactory.setPort(6379);
        connectionFactory.setHostName("localhost");
        return connectionFactory;
    }
}

And then it's done, it's so easy. Make a request in the browser, and then you can find the following content in Redis:

image

Without explaining the specific meaning of the data stored in Redis, let's first study what the @EnableRedisHttpSession annotation does for us. So, look at the source code and go. . .

@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ java.lang.annotation.ElementType.TYPE })
@Documented
@Import(RedisHttpSessionConfiguration.class)
@Configuration
public @interface EnableRedisHttpSession {
    /* */
}

This annotation contains an important @Import annotation, which supports importing ordinary java classes and declaring them as a bean. So after using @EnableRedisSession, it is equivalent to declaring a RedisHttpSessionConfiguration bean at the same time. Then look at how this class is defined:

@Configuration
@EnableScheduling
public class RedisHttpSessionConfiguration extends SpringHttpSessionConfiguration
        implements EmbeddedValueResolverAware, ImportAware {
    @Bean
    public RedisTemplate<Object, Object> sessionRedisTemplate(
            RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashKeySerializer(new StringRedisSerializer());
        if (this.defaultRedisSerializer != null) {
            template.setDefaultSerializer(this.defaultRedisSerializer);
        }
        template.setConnectionFactory(connectionFactory);
        return template;
    }

    @Bean
    public RedisOperationsSessionRepository sessionRepository(
            @Qualifier("sessionRedisTemplate") RedisOperations<Object, Object> sessionRedisTemplate,
            ApplicationEventPublisher applicationEventPublisher) {
        RedisOperationsSessionRepository sessionRepository = new RedisOperationsSessionRepository(
                sessionRedisTemplate);
        sessionRepository.setApplicationEventPublisher(applicationEventPublisher);
        sessionRepository
                .setDefaultMaxInactiveInterval (this.maxInactiveIntervalInSeconds);
        if (this.defaultRedisSerializer != null) {
            sessionRepository.setDefaultSerializer(this.defaultRedisSerializer);
        }

        String redisNamespace = getRedisNamespace();
        if (StringUtils.hasText(redisNamespace)) {
            sessionRepository.setRedisKeyNamespace (redisNamespace);
        }

        sessionRepository.setRedisFlushMode (this.redisFlushMode);
        return sessionRepository;
    }

}

Several important beans are declared in RedisHttpSessionConfiguration. The above code snippet actually implements Redis-related configuration. The dependencies are RedisOperationsSessionRepository => sessionRedisTemplate => RedisConnectionFactory. At the same time, RedisHttpSessionConfiguration inherits from SpringHttpSessionConfiguration. And SpringHttpSessionConfiguration itself will declare a springSessionRepositoryFilter, this filter acts on the global, session saving and invalidation are done here. For the specific implementation of this filter, we will not analyze it here, because it still operates Redis to save the session by calling RedisOperationsSessionRepository.

There is actually quite a lot of RedisOperationsSessionRepository implementation code, but the logic is not complicated, so there is no need to paste a lot of code. Just look at the function saved by Session!

    public void save(RedisSession session) {
        session.saveDelta ();
        if (session.isNew()) {
            String sessionCreatedKey = getSessionCreatedChannel(session.getId());
            this.sessionRedisOperations.convertAndSend(sessionCreatedKey, session.delta);
            session.setNew(false);
        }
    }

There is not much, sessionRedisOperations.convertAndSend() completes the saving of session data. So how is the session data in Redis stored? For a session data, two key/values ​​are stored in Redis, one of which stores the actual session data, and the other is used to assist in the processing of session expiration. In addition, there is an overall data for recording expired sessions. The following is a typical storage form:

* HMSET spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe creationTime 1404360000000 maxInactiveInterval 1800 lastAccessedTime 1404360000000 sessionAttr:attrName someAttrValue sessionAttr2:attrName someAttrValue2
 * EXPIRE spring:session:sessions:33fdd1b6-b496-4b33-9f7d-df96679d32fe 2100
 * APPEND spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe ""
 * EXPIRE spring:session:sessions:expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe 1800
 * SADD spring:session:expirations:1439245080000 expires:33fdd1b6-b496-4b33-9f7d-df96679d32fe
 * EXPIRE spring:session:expirations1439245080000 2100

The first storage command is the actual session data. This data is stored in the form of HashSet in Redis, and various data can be stored in it. The third storage command is the expired data of the auxiliary session, which will be longer than the actual data in the expire time, which is used to distinguish whether a session has timed out or does not exist. The fifth storage command is the overall session expiration record, which is a collection. The significance of this overall expirations set is that Redis's timeout is imprecise, and there may be a session that has expired (the auxiliary session data has also expired), but it still exists in Redis. This is because Redis's data timeout clearing task is low priority. With the overall session expiration record, this problem can be solved. When Redis really clears the data (there will be an event notification), then delete the session from the expirations collection.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324774652&siteId=291194637
Recommended