Add two level of caching

This commit is contained in:
saikat 2024-02-28 14:52:16 +05:30
parent c5a3c01108
commit 43a168a525
8 changed files with 247 additions and 2 deletions

View File

@ -0,0 +1,90 @@
package com.baeldung.caching.multicache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.AnnotationCacheOperationSource;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.cache.interceptor.CacheOperationSource;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.time.Duration;
import java.util.Arrays;
@Configuration
@EnableCaching
public class CacheConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
@Bean
public CaffeineCache caffeineCacheConfig() {
return new CaffeineCache("customerCache", Caffeine.newBuilder()
.expireAfterWrite(Duration.ofMinutes(1))
.initialCapacity(1)
.maximumSize(2000)
.build());
}
@Bean
@Primary
public CacheManager caffeineCacheManager() {
SimpleCacheManager manager = new SimpleCacheManager();
manager.setCaches(Arrays.asList(
caffeineCacheConfig()));
return manager;
}
@Bean
public CacheManager redisCacheManager() {
return RedisCacheManager.RedisCacheManagerBuilder
.fromConnectionFactory(redisConnectionFactory())
.withCacheConfiguration("customerCache", cacheConfiguration())
.build();
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
redisStandaloneConfiguration.setHostName(redisHost);
redisStandaloneConfiguration.setPort(redisPort);
return new LettuceConnectionFactory(redisStandaloneConfiguration);
}
@Bean
public RedisCacheConfiguration cacheConfiguration() {
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(60))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()));
}
@Bean
public CacheInterceptor cacheInterceptor() {
CacheInterceptor interceptor = new CustomerCacheInterceptor(caffeineCacheManager());
interceptor.setCacheOperationSources(cacheOperationSource());
return interceptor;
}
@Bean
public CacheOperationSource cacheOperationSource() {
return new AnnotationCacheOperationSource();
}
}

View File

@ -0,0 +1,21 @@
package com.baeldung.caching.multicache;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.Setter;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Setter
public class Customer implements Serializable {
private String id;
private String name;
private String email;
}

View File

@ -0,0 +1,30 @@
package com.baeldung.caching.multicache;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheInterceptor;
import org.springframework.data.redis.cache.RedisCache;
public class CustomerCacheInterceptor extends CacheInterceptor {
private final CacheManager caffeineCacheManager;
public CustomerCacheInterceptor(CacheManager caffeineCacheManager) {
this.caffeineCacheManager = caffeineCacheManager;
}
@Override
protected Cache.ValueWrapper doGet(Cache cache, Object key) {
Cache.ValueWrapper existingCacheValue = super.doGet(cache, key);
if (cache.getClass() == RedisCache.class) {
Cache caffeineCache = caffeineCacheManager.getCache(cache.getName());
if (existingCacheValue != null && caffeineCache != null && caffeineCache.get(key) == null) {
caffeineCache.putIfAbsent(key, existingCacheValue.get());
}
}
return existingCacheValue;
}
}

View File

@ -0,0 +1,22 @@
package com.baeldung.caching.multicache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class CustomerController {
private final CustomerService customerService;
@Autowired
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping("/customer/{id}")
public Customer getCustomer(@PathVariable String id) {
return customerService.getCustomer(id);
}
}

View File

@ -0,0 +1,44 @@
package com.baeldung.caching.multicache;
import org.springframework.stereotype.Service;
import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;
@Service
public class CustomerRepository {
private final Map<String, Customer> customerMap = new HashMap<>();
public Customer getCustomerById(String id) {
return customerMap.get(id);
}
@PostConstruct
private void setupCustomerRepo() {
Customer product1 = getCustomer("100001", "name1", "name1@mail.com");
customerMap.put("100001", product1);
Customer product2 = getCustomer("100002", "name2", "name2@mail.com");
customerMap.put("100002", product2);
Customer product3 = getCustomer("100003", "name3", "name3@mail.com");
customerMap.put("100003", product3);
Customer product4 = getCustomer("100004", "name4", "name4@mail.com");
customerMap.put("100004", product4);
Customer product5 = getCustomer("100005", "name5", "name5@mail.com");
customerMap.put("100005", product5);
}
private static Customer getCustomer(String id, String name, String email) {
Customer customer = new Customer();
customer.setId(id);
customer.setName(name);
customer.setEmail(email);
return customer;
}
}

View File

@ -0,0 +1,25 @@
package com.baeldung.caching.multicache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
@Autowired
public CustomerService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
@Caching(cacheable = {
@Cacheable(cacheNames = "customerCache", cacheManager = "caffeineCacheManager"),
@Cacheable(cacheNames = "customerCache", cacheManager = "redisCacheManager")
})
public Customer getCustomer(String id) {
return customerRepository.getCustomerById(id);
}
}

View File

@ -0,0 +1,12 @@
package com.baeldung.caching.multicache;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MultipleCachingApplication {
public static void main(String[] args) {
SpringApplication.run(MultipleCachingApplication.class, args);
}
}

View File

@ -9,5 +9,6 @@ spring.jpa.hibernate.ddl-auto=update
#setting cache TTL
caching.spring.hotelListTTL=43200
# Connection details
#spring.redis.host=localhost
#spring.redis.port=6379
spring.redis.host=localhost
spring.redis.port=6379
spring.main.allow-bean-definition-overriding=true