Skip to content

Impossible to provide a Custom SessionRepository #1406

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
herveDarritchon opened this issue Apr 26, 2019 · 3 comments
Closed

Impossible to provide a Custom SessionRepository #1406

herveDarritchon opened this issue Apr 26, 2019 · 3 comments
Assignees

Comments

@herveDarritchon
Copy link

herveDarritchon commented Apr 26, 2019

In a spring-boot context( v2.1.5.RELEASE), I use spring-session (2.1.4.RELEASE) with REDIS. But in our premise infrastructure, REDIS comes with Dynomite from Netflix to do the cross datacenter replication and high availability. And Dynomite doesn’t support PUB/SUB commands.
So we need to write our own custom sessionRepository with no pub/sub commands.
It’s where I have an issue with Spring Boot Autoconfiguration, I should be able to do easily this customization if I trust the documentation (https://docs.spring.io/spring-session/docs/current-SNAPSHOT/reference/html/custom-sessionrepository.html#custom-sessionrepository).

But I failed to do this. I asked questions in Gitter, firstly in Spring-Session with no succes () and after in Spring-Boot, where I have been suggested to raise an issue by Andy Wilkinson @wilkinsona.

please find below some part of our code.

dependencies in a build.gradle

val springBootVersion = "2.1.4.RELEASE"
val springSessionDataRedisVersion = "2.1.5.RELEASE"

implementation("org.springframework.boot:spring-boot-starter-security:$springBootVersion")
implementation("org.springframework.boot:spring-boot-starter-thymeleaf:$springBootVersion")
implementation("org.springframework.boot:spring-boot-starter-web:$springBootVersion")
implementation("org.springframework.boot:spring-boot-starter-data-redis:$springBootVersion")
implementation("org.springframework.session:spring-session-data-redis:$springSessionDataRedisVersion")

Our configuration class to override the sessionRepository with our custom one

@Configuration
@EnableRedisHttpSession
public class SessionConfig extends AbstractHttpSessionApplicationInitializer     {

@Bean
@Primary
public SessionRepository sessionRepository() {
    return new RedisDynoSessionRepository();
    }
}

The sessionRepository custom class

public class RedisDynoSessionRepository implements
    FindByIndexNameSessionRepository<RedisDynoSessionRepository.RedisSession>
...
}

When we run our app, we have a collision in the bean because the app finds that the bean session repository is already known.

org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'sessionRepository' defined in class path resource [com/orange/ccmd/spring/redis/SessionConfig.class]: Cannot register bean definition [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=sessionConfig; factoryMethodName=sessionRepository; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [com/orange/ccmd/spring/redis/SessionConfig.class]] for bean 'sessionRepository': There is already [Root bean: class [null]; scope=; abstract=false; lazyInit=false; autowireMode=3; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration; factoryMethodName=sessionRepository; initMethodName=null; destroyMethodName=(inferred); defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]] bound.

If we use the bean override configuration of spring-boot :

spring.main.allow-bean-definition-overriding=true

Spring complains because there are not the same types

[11:28:49.894] WARN   [nConfigServletWebServerApplicationContext] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'redisMessageListenerContainer' defined in class path resource [org/springframework/session/data/redis/config/annotation/web/http/RedisHttpSessionConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.data.redis.listener.RedisMessageListenerContainer]: Factory method 'redisMessageListenerContainer' threw exception; nested exception is java.lang.IllegalStateException: @Bean method RedisHttpSessionConfiguration.sessionRepository called as bean reference for type [org.springframework.session.data.redis.RedisOperationsSessionRepository] but overridden by non-compatible bean instance of type [com.orange.ccmd.spring.redis.RedisDynoSessionRepository]. Overriding bean of same name declared in: class path resource [com/orange/ccmd/spring/redis/SessionConfig.class]

I’d like to know the proper way to provide my own implementation of a sessionRepository to Spring and I'd like to know if there is an issue in Spring Session or not ?

from Spring Session gitter :

I don't think this is a problem with Boot's auto-configuration. It will back off when you declare your own SessionRepository bean
It looks like a couple of Spring Session problems to me:
It seems to rely on bean definition overriding to allow a custom SessionRepository to be configured
When bean definition overriding is permitted, RedisHttpSessionConfiguration makes some assumptions about the type of the SessionRepository which do not hold true

Andy Wilkinson @wilkinsona 12:32
If I were you, I would open a Spring Session issue. Ideally, Spring Session would allow repository customization with bean definition overriding disabled. Putting that aside, I think a change is still needed to RedisHttpSessionConfiguration regardless

@vpavic vpavic self-assigned this Apr 26, 2019
@vpavic
Copy link
Contributor

vpavic commented Apr 26, 2019

As stated in the reference manual that you linked, to reuse core Spring Session infrastructure and provide your own SessionRepository implementation you need to use @EnableSpringHttpSession annotation.

The problem you are facing is caused by use of @EnableRedisHttpSession that is focused on configuring RedisOperationsSessionRepository.

Does this help?

@vpavic vpavic added the status: waiting-for-feedback We need additional information before we can continue label Apr 26, 2019
@herveDarritchon
Copy link
Author

herveDarritchon commented Apr 27, 2019

@vpavic Yes, it helps a lot, it puts me on the good track :) Thanks a lot !
I should have seen that @EnableRedisHttpSession imports @EnableSpringHttpSession imports @Import(RedisHttpSessionConfiguration.class) whereas @Import(SpringHttpSessionConfiguration.class).
I am a kind of newbie in this so sorry to have raised an issue where as it was written in the documentation. May be not so clear for junior people like :)
Thanks for your help. I will keep working on my custom repository.

Do you think it would be interesting to propose it as a PR or may be a link somewhere if it's good enough as I saw that other people ask for such a thing ?

@vpavic
Copy link
Contributor

vpavic commented Apr 27, 2019

Glad to hear that helped @herveDarritchon. Regarding community extensions, if you decide to create a project around your custom SessionRepository implementation, feel free to either open an issue or PR to add it to community extensions section of our reference manual.

@vpavic vpavic closed this as completed Apr 27, 2019
@vpavic vpavic added status: invalid and removed status: waiting-for-feedback We need additional information before we can continue labels Apr 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants