Spring Session MapSessionRepository - spring

I am attempting to use a MapSessionRepository and HttpSessionEventPublisher in Spring Session declared like this:
#Bean
public MapSessionRepository sessionRepository() {
return new MapSessionRepositoryImpl(new ConcurrentHashMap<>());
}
#Bean
public HttpSessionEventPublisher eventPublisher() {
return new HttpSessionEventPublisher();
}
I also have
In the javadoc for the class, I see the following:
The implementation does NOT support firing {#link SessionDeletedEvent} or {#link SessionExpiredEvent}.
To me, this implies that it should support the basic SessionCreatedEvent and SessionDestroyedEvent, but nothing seems to be published.
Since I'm not trying to use one of the full distributed data stores, I have this in my application.properties:
spring.session.store-type=none
My question is, will the MapSessionRepository support publishing events if it's initialized with a ConcurrentHashMap?

Related

Programmatic RedissonClient in Spring boot project

I am trying to implement Hibernate second level caching in a Spring boot project using Redisson.
I have followed this blog as a reference
https://pavankjadda.medium.com/implement-hibernate-2nd-level-cache-with-redis-spring-boot-and-spring-data-jpa-7cdbf5632883
Also i am trying to initialize the RedissionClient programmatically and not through declaratively /through a config file
Created a spring bean to be initialized which should create the RedissonClient instance.
#Configuration
#Lazy(value = false)
public class RedissonConfig {
#Bean
public RedissonClient redissionClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
return Redisson.create(config);
}
}
However this bean is never intialized and i get the following error while application startup.
Caused by: org.hibernate.cache.CacheException: Unable to locate Redisson configuration
at org.redisson.hibernate.RedissonRegionFactory.createRedissonClient(RedissonRegionFactory.java:107) ~[redisson-hibernate-53-3.12.1.jar:3.12.1]
at org.redisson.hibernate.RedissonRegionFactory.prepareForUse(RedissonRegionFactory.java:83) ~[redisson-hibernate-53-3.12.1.jar:3.12.1]
It seems Spring boot Hibernate still trying to load the Redisson config through a config file.
is it possible to load the Redission config in spring boot programmatically ?
Best Regards,
Saurav
I just did exactly this, here is how:
you need a custom RegionFactory that is similar to the JndiRedissonRegionFactory but gets its RedissonClient injected somehow.
an instance of this Class, fully configured, is put into the hibernate-properties map. Hibernates internal code is flexible: if the value of hibernate.cache.region.factory_class is a string it is treated as a FQDN. If it is an instance of Class<?>, it will be instantiated. If it is an Object, it will be used.
Spring offers a rather simple way to customize hibernate properties with a bean:
#AutoConfiguration(after = RedissonAutoConfiguration.class, before = JpaAutoConfiguration.class)
#ConditionalOnProperty("spring.jpa.properties.hibernate.cache.use_second_level_cache")
public class HibernateCacheAutoConfiguration {
#Bean
public HibernatePropertiesCustomizer setRegionFactory(RedissonClient redisson) {
return hibernateProperties -> hibernateProperties.put(AvailableSettings.CACHE_REGION_FACTORY, new SpringBootRedissonRegionFactory(redisson));
}
}
My RegionFactory is really simple:
#AllArgsConstructor
public class SpringBootRedissonRegionFactory extends RedissonRegionFactory {
private RedissonClient redissonClient;
#Override
protected RedissonClient createRedissonClient(Map properties) {
return redissonClient;
}
#Override
protected void releaseFromUse() {
}
}
I used the redisson-starter to get a RedissonClient, hence the reference to RedissonAutoConfiguration, but you could just create an instance by hand.
It is possible, but then you need to provide a custom implementation of RegionFactory to Hibernate, which can extends RedissonRegionFactory but uses your own client instance.

How to configure request timeouts in Spring Cloud Gateway via code

I need to configure request timeouts in code for all routes. I know global timeouts can be configured via following properties in application.properties, but how can they be configured in code?
spring.cloud.gateway.httpclient.connect-timeout=1000
spring.cloud.gateway.httpclient.response-timeout=5s
I have looked at GatewayAutoConfiguration how timeouts are configured by default. HttpClientProperties holds both properties, however it cannot be overwritten.
#Bean
public HttpClientProperties httpClientProperties() {
return new HttpClientProperties();
}
Can this be done in code?
I solved my problem. I created my own bean and used annotation #Primary to be able to create a separate bean with the same type. GatewayAutoConfiguration now uses my bean instead of the default bean.
#Bean
#Primary
public HttpClientProperties overwrittenHttpClientProperties() {
HttpClientProperties p = new HttpClientProperties();
p.setConnectTimeout(3000);
p.setResponseTimeout(Duration.ofMillis(10000));
return p;
}

Spring Boot Transaction support using #transactional annotation not working with mongoDB, anyone have solution for this?

Spring Boot version - 2.4.4,
mongodb version - 4.4.4
In my project, I want to do entry in 2 different document of mongodb, but if one fails than it should do rollback. mongodb supports transaction after version 4.0 but only if you have at least one replica set.
In my case I don't have replica set and also cannot create it according to my project structure. I can't use transaction support of mongodb because no replica-set. So, I am using Spring Transaction.
According to spring docs, to use transaction in Spring Boot, you only need to use #transactional annotation and everything will work(i.e. rollback or commit).
I tried many things from many sources but it is not rollbacking transaction if one fail.
Demo code is here,
This is demo code, not actual project.
This is my service class.
#Service
public class UserService {
#Autowired
UserRepository userRepository;
#Autowired
UserDetailRepository userDetailRepository;
#Transactional(rollbackFor = Exception.class)
public ResponseEntity<JsonNode> createUser(SaveUserDetailRequest saveUserDetailRequest) {
try {
User _user = userRepository.save(new User(saveUserDetailRequest.getId(), saveUserDetailRequest.getFirstName(), saveUserDetailRequest.getLastName()));
UserDetail _user_detail = userDetailRepository.save(new UserDetail(saveUserDetailRequest.getPhone(), saveUserDetailRequest.getAddress()));
} catch (Exception m) {
System.out.print("Mongo Exception");
}
return new ResponseEntity<>(HttpStatus.OK);
}
}
Also tried below code but still not working,
#EnableTransactionManagement
#Configuration
#EnableMongoRepositories({ "com.test.transaction.repository" })
#ComponentScan({"com.test.transaction.service"})
public class Config extends AbstractMongoClientConfiguration{
private com.mongodb.MongoClient mongoClient;
#Bean
MongoTransactionManager transactionManager(MongoDbFactory dbFactory) {
return new MongoTransactionManager(dbFactory);
}
#Bean
public com.mongodb.MongoClient mongodbClient() {
mongoClient = new com.mongodb.MongoClient("mongodb://localhost:27017");
return mongoClient;
}
#Override
protected String getDatabaseName() {
return "test";
}
}
The transaction support in Spring is only there to make things easier, it doesn't replace the transaction support for the underlying datastore being used.
In this case, it will simply delegate the starting/committing of a transaction to MongoDB. WHen using a database it will eventually delegate to the database etc.
As this is the case, the pre-requisites for MongoDB still need to be honoured and you will still need a replica.

Spring retry - can #Recover be in standalone class?

I have a Spring Integration app with multiple endpoint that process the same data in different ways.
They all have identical '#Recover' methods which has become boilerplate and seems fragile.
Can you you centralize the #Recover method (e.g. in a standalone class) and/or can you specify how to find this #Recover annotated method?
It's not clear why would one use a #Retryable in Spring Integration when there is that RequestHandlerRetryAdvice: https://docs.spring.io/spring-integration/docs/current/reference/html/messaging-endpoints.html#message-handler-advice-chain...
Anyway see this option on the #Retryable:
/**
* Retry interceptor bean name to be applied for retryable method. Is mutually
* exclusive with other attributes.
* #return the retry interceptor bean name
*/
String interceptor() default "";
So, instead of #Recover method you provide your own:
#Bean
public MethodInterceptor retryInterceptor() {
return RetryInterceptorBuilder.stateless()
.maxAttempts(...)
.recoverer(...)
.build();
}
...
#Retryable(interceptor = "retryInterceptor")
public void service() {

Spring session with in memory store

Why does not spring.session.store-type has in memory option. ?
Is there any way to use spring session with in memory option without writing my implementation of store ?
I would like to use spring session for rest api with token
#Bean
public HttpSessionIdResolver httpSessionIdResolver() {
return HeaderHttpSessionIdResolver.xAuthToken();
}
I found solution, there is a MapSessionRepository which can accept map.
here is a documentation EnableSpringHttpSession
#EnableSpringHttpSession
#Configuration
public class SpringHttpSessionConfig {
#Bean
public MapSessionRepository sessionRepository() {
return new MapSessionRepository(new ConcurrentHashMap<>());
}
}

Resources