Redis cache docker container with spring boot not working on my local Machine - spring

I am using redis cache on my local Machine as a docker image. I have enabled the cache for one of my method using the cacheable anothion. Application is not able to cache the same when i am using on aws it is working instead of localhost
public class RedisConfig {
#Autowired
private JedisConnectionFactory jedisConnectionFactory;
#Bean
public RedisTemplate<Object, Object> redisTemplate() {
System.out.println("localhost")
System.out.println("6379");
jedisConnectionFactory.getHostName();
jedisConnectionFactory.getPort();
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(jedisConnectionFactory);
template.setValueSerializer(new GenericToStringSerializer<Object>(Object.class));
return template;
}
#Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate);
// Number of seconds before expiration. Defaults to unlimited (0)
cacheManager.setDefaultExpiration(60);
cacheManager.setUsePrefix(true);
return cacheManager;
}
}
#Cacheable(value="sgcode" , cacheManager ="cacheManager")
public String getSegmentCode(String aname ) {
Logger.info("code ", "##### SEGMENT METHOD CALLED ##### {}", aname);
return segmentCodeMap.get(aname);
}
Logger line will be printed only once after that it should fetch from cache.

Finally after lot of struggle found the root cause. use the enablecaching anotation in application class

Related

Multiple Redis For Spring Cache And JWT

I have actually an application that is using Redis for Cache and keeping the JWT token into redis.
My goal is to have one redis for cache, and another one for jwt token.
I dont understand how i can achieve this.
How can i say to spring to use a specific redis (here "redis-cache") for caching ?
Actually i only put #EnableCaching and it is working properly
Thanks for any help
spring:
redis:
port: 7000
password: password123
host: 127.0.0.1
redis-cache: # New One
port: 7001
password: password123
host: 127.0.0.1
I'm using redisTemplate to keep jwt token into redis
#Configuration
public class GenericBeanConfig {
#Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
Jackson2JsonRedisSerializer<String> jrs = new Jackson2JsonRedisSerializer<String>(String.class);
template.setKeySerializer(jrs);
template.setConnectionFactory(connectionFactory);
return template;
}
}
...
#EnableCaching
public class ProjectsApplication {
public static void main(String[] args) {
SpringApplication.run(ProjectsApplication .class, args);
}
}
Caching some endpoint
#Cacheable(value = "users-rbac")
public UserResponseDTO search(#PathVariable String email) {
return userService.search(email);
}
You can define your custom CacheManager as well, you define your cache manager as follows. Customize this as you see, for now host, port and password are fixed but you can read them from application config file using #Value .
#Bean
public CacheManager cacheManager() {
// create redis configuration
RedisStandaloneConfiguration configuration =
new RedisStandaloneConfiguration("127.0.0.1", 7001);
configuration.setPassword(RedisPassword.of("password"));
// create a connection factory, use other connection factory if you want
LettuceConnectionFactory factory = new LettuceConnectionFactory(configuration);
factory.afterPropertiesSet();
RedisCacheWriter writer = RedisCacheWriter.nonLockingRedisCacheWriter(factory);
// define cache cnfiguration
RedisCacheConfiguration cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
// use Jackson serdes do not use JDK one
cacheConfiguration.serializeValuesWith(
SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
// create cache manager
return new RedisCacheManager(writer, cacheConfiguration);
}

Java JobRunr when using Spring Boot Redis Starter

How do I create and use the Redis connection that spring-boot-starter-data-redis creates? It doesn't seem like there is a Bean for RedisClient created by the default auto configuration so I'm not sure of the best way to do this.
The documentation does state that in this case you need to create the StorageProvider yourself which is fine, but can you reuse what Spring Boot has already created. I believe this would need to be a pooled connection which you would also need to enable through Spring Boot.
RedisTemplate offers a high-level abstraction for Redis interactions:
https://docs.spring.io/spring-data/data-redis/docs/current/reference/html/#redis:template
Redis autoconfiguration :
#AutoConfiguration
#ConditionalOnClass({RedisOperations.class})
#EnableConfigurationProperties({RedisProperties.class})
#Import({LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class})
public class RedisAutoConfiguration {
public RedisAutoConfiguration() {
}
#Bean
#ConditionalOnMissingBean(
name = {"redisTemplate"}
)
#ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<Object, Object> template = new RedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
#Bean
#ConditionalOnMissingBean
#ConditionalOnSingleCandidate(RedisConnectionFactory.class)
public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
return new StringRedisTemplate(redisConnectionFactory);
}
}
Here you can find the corresponding configuration properties(including connection pool default configuration).
Simple implementation example :
https://www.baeldung.com/spring-data-redis-tutorial

How to enable distributed/clustered cache when using redis with spring data cache

How to enable distributed/clustered cache when using Redis with spring-boot cache.
Especially when using Redis through spring-boot-starter-data-redis
Enable caching in the spring boot app is very simple. You would need to just follow three steps.
Define cache configuration
Add EnableCaching to any configuration class
Provide a CacheManager bean
For Redis, we've RedisCacheManager that can be configured and created.
Cache Configuration
#Configuration
#Getter
#Setter
#ConfigurationProperties(prefix = "cache")
public class CacheConfigurationProperties {
// Redis host name
private String redisHost;
// Redis port
private int redisPort;
// Default TTL
private long timeoutSeconds;
// TTL per cache, add enties for each cache
private Map<String, Long> cacheTtls;
}
Set their values via properties or yaml file like
cache.redisHost=localhost
cache.redisPort=6379
cache.timeoutSeconds=1000
cache.cacheTtls.cach1=100
cache.cacheTtls.cach2=200
Once you have created configuration, you can create cache config for RedisCacheManger by builder.
#Configuration
#EnableCaching
public class CacheConfig {
private static RedisCacheConfiguration createCacheConfiguration(long timeoutInSeconds) {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(timeoutInSeconds));
}
#Bean
public LettuceConnectionFactory redisConnectionFactory(CacheConfigurationProperties properties) {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(properties.getRedisHost());
redisStandaloneConfiguration.setPort(properties.getRedisPort());
return new LettuceConnectionFactory(redisStandaloneConfiguration);
}
#Bean
public RedisCacheConfiguration cacheConfiguration(CacheConfigurationProperties properties) {
return createCacheConfiguration(properties.getTimeoutSeconds());
}
#Bean
public CacheManager cacheManager(
RedisConnectionFactory redisConnectionFactory, CacheConfigurationProperties properties) {
Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
for (Entry<String, Long> cacheNameAndTimeout : properties.getCacheTtls().entrySet()) {
cacheConfigurations.put(
cacheNameAndTimeout.getKey(), createCacheConfiguration(cacheNameAndTimeout.getValue()));
}
return RedisCacheManager.builder(redisConnectionFactory)
.cacheDefaults(cacheConfiguration(properties))
.withInitialCacheConfigurations(cacheConfigurations)
.build();
}
}
If you're using Redis cluster than update cache properties as per that. In this some beans would become primary if you want cache specific bean than make these methods private.

Register Caffeine Cache in Spring Actuator (CacheManager)

We're using Spring Boot 2 and Spring Actuator. When creating a cache like the following:
#Bean
public CaffeineCache someCache() {
return new CaffeineCache("my-cache",
Caffeine.newBuilder()
.maximumSize(1000)
.expireAfterWrite(10, TimeUnit.SECONDS)
.build());
}
it is registered into Spring Actuator and can be accessed and handle via endpoints:
❯ http GET localhost:8080/actuator/caches
{
"cacheManagers": {
"cacheManager": {
"caches": {
"my-cache": {
"target": "com.github.benmanes.caffeine.cache.BoundedLocalCache$BoundedLocalManualCache"
}
}
}
}
}
However, this is valid when using the annotation #Cacheable - but I would like to create a cache and use it as a map.
Therefore, I can create:
#Bean
public com.github.benmanes.caffeine.cache.Cache<String, MyObject> customCache(QueryServiceProperties config) {
return Caffeine.newBuilder()
.maximumSize(10)
.expireAfterAccess(10, TimeUnit.SECONDS)
.build();
}
And it works but it cannot be discovered by Spring Actuator. Is there any way to register this kind of cache?
Addapted from this Answer I did the following:
#Autowired
private CacheMetricsRegistrar cacheMetricsRegistrar;
private LoadingCache<Key, MyObject> cache;
#PostConstruct
public void init() {
cache = Caffeine.newBuilder()
.maximumSize(10_000)
.refreshAfterWrite(cacheDuration)
.recordStats()
.build(this::loadMyObject);
// trick the compiler
Cache tmp = cache;
cacheMetricsRegistrar.bindCacheToRegistry(new CaffeineCache(CACHE_NAME, tmp), Tag.of("name", CACHE_NAME));
}
The Cache should now show up in the cache actuator endpoints, e.g. "http://localhost:8080/metrics/cache.gets"
use CacheManager
add your custom cache into CacheManager, inject CacheManager and get that cache out for your usage.
see https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-caching.html for some further details

Collisions may occur when using Spring #Cacheable and SimpleKeyGenerator

When I use #Cacheable and call different method with same parameter, it generated a same key.
SimpleKeyGenerator generated key without cache names.
I use spring-boot 1.3.2 with spring 4.2.4.
Here is a sample:
#Component
public static class CacheableTestClass {
#Cacheable(cacheNames = "test-cacheproxy-echo1")
public String echo1(String text) {
return text;
}
#Cacheable(cacheNames = "test-cacheproxy-echo2")
public String echo2(String text) {
return "Another " + text;
}
}
And run a test:
assertEquals("OK", cacheableTestClass.echo1("OK"));
assertEquals("Another OK", cacheableTestClass.echo2("OK")); // Failure: expected 'Another OK', actual 'OK'.
So, is there a way to resolve this issue?
Thanks a lot.
Update
Here is my CacheManager configuration.
#Bean
#ConditionalOnMissingBean(name = "cacheRedisTemplate")
public RedisTemplate<Object, Object> cacheRedisTemplate(
RedisConnectionFactory redisConnectionFactory)
throws UnknownHostException {
RedisTemplate<Object, Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
template.setHashKeySerializer(template.getKeySerializer());
return template;
}
#Bean
public RedisCacheManager cacheManager(#Qualifier("cacheRedisTemplate") RedisTemplate<Object, Object> cacheRedisTemplate) {
RedisCacheManager cacheManager = new RedisCacheManager(cacheRedisTemplate);
cacheManager.setDefaultExpiration(
redisCacheProperties().getDefaultExpiration());
cacheManager.setExpires(redisCacheProperties().getExpires());
return cacheManager;
}
This has nothing to do with SimpleKeyGenerator but this is a redis-specific issue that does not use the name of the cache as a discriminant for the key it uses to store the value.
You need to invoke setUsePrefix(true) on your RedisCacheManager. This is what Spring Boot does when it auto-configures the cache manager for you. Note that it should have been the default and we're discussing how we can improve the out-of-the-box experience in a future release

Resources