3131import org .springframework .context .annotation .Import ;
3232import org .springframework .core .env .Environment ;
3333import org .springframework .data .redis .connection .RedisConnectionFactory ;
34+ import org .springframework .data .redis .core .RedisOperations ;
35+ import org .springframework .session .MapSession ;
3436import org .springframework .session .config .SessionRepositoryCustomizer ;
3537import org .springframework .session .data .redis .RedisIndexedSessionRepository ;
38+ import org .springframework .session .data .redis .RedisSessionMapper ;
3639
40+ import java .util .Map ;
3741import java .util .Objects ;
42+ import java .util .function .BiFunction ;
3843
3944@ Configuration
4045@ ConditionalOnProperty (name = "spring.session.store-type" , havingValue = "redis" )
@@ -59,7 +64,10 @@ public String getRedisNamespace() {
5964
6065 @ Bean
6166 public SessionRepositoryCustomizer <RedisIndexedSessionRepository > sessionRepositorySessionRepositoryCustomizer () {
62- return redisIndexedSessionRepository -> redisIndexedSessionRepository .setRedisKeyNamespace (redisNamespace );
67+ return redisIndexedSessionRepository -> {
68+ redisIndexedSessionRepository .setRedisKeyNamespace (redisNamespace );
69+ redisIndexedSessionRepository .setRedisSessionMapper (new SafeRedisSessionMapper (redisIndexedSessionRepository .getSessionRedisOperations ()));
70+ };
6371 }
6472
6573 @ Bean
@@ -84,4 +92,28 @@ public Health health() {
8492 }
8593 }
8694
95+ class SafeRedisSessionMapper implements BiFunction <String , Map <String , Object >, MapSession > {
96+
97+ private final RedisSessionMapper delegate = new RedisSessionMapper ();
98+
99+ private final RedisOperations <String , Object > redisOperations ;
100+
101+ SafeRedisSessionMapper (RedisOperations <String , Object > redisOperations ) {
102+ this .redisOperations = redisOperations ;
103+ }
104+
105+ @ Override
106+ public MapSession apply (String sessionId , Map <String , Object > map ) {
107+ try {
108+ return this .delegate .apply (sessionId , map );
109+ }
110+ catch (IllegalStateException ex ) {
111+ // do not invoke RedisIndexedSessionRepository#deleteById to avoid an infinite loop because the method also invokes this mapper
112+ redisOperations .delete (getRedisNamespace () + ":sessions:" + sessionId );
113+ return null ;
114+ }
115+ }
116+
117+ }
118+
87119}
0 commit comments