一:目录结构
二:分而治之
redis和caffeine有各自的bean目录 自定义实现的bean(xxxxCache,Manager,Configuration,CacheResolve)等可以放在这里
redis和caffeine有各自的配置目录,分开配置自己的bean,序列化等
分而治之,回归一统:单独配置好Redis,单独配置好Caffeine,最后交给合并缓存(CaffeineRedis)进行数据操作
三:application.yml配置文件
spring:
#自定义管理缓存
custom-manager:
isOpen-custom-cache: true #是否开启管理缓存
#选择开启的缓存类型
#caffeine:开启Caffeine一级缓存
#redis:开启Redis一级缓存
#caffeine-redis:开启一二级缓存,caffeine为一级缓存,redis为二级缓存
cache-type: caffeine-redis
#cache-type: redis
redis:
database: 0
host: *******
port: 6379
password: 123456
# jedis:
# pool:
# #连接池最大连接数
# max-active: 8
# #连接池最大阻塞等待时间
# max-wait: -1
# #连接池最大空闲连接数
# max-idle: 500
# #连接池最小空闲连接数
# min-idle: 0
lettuce:
pool:
max-wait: -1
max-idle: 8
min-idle: 0
max-active: 8
shutdown-timeout: 0
**
四:Redis
CustomeRedisCacheWriter类
这个类对象是RedisCache的一个属性 当操作redisCache时,redisCache会对redisCacheWriter对象操作
public class CustomeRedisCacheWriter implements RedisCacheWriter {
private final RedisConnectionFactory connectionFactory;
private final Duration sleepTime;
public CustomeRedisCacheWriter(RedisConnectionFactory connectionFactory){
this(connectionFactory, Duration.ZERO);
}
public CustomeRedisCacheWriter(RedisConnectionFactory connectionFactory,Duration sleepTime){
this.connectionFactory=connectionFactory;
this.sleepTime=sleepTime;
}
@Override
public void put(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
this.execute(name, (connection) -> {
if (shouldExpireWithin(ttl)) {
connection.set(key, value, Expiration.from(ttl.toMillis(), TimeUnit.MILLISECONDS), RedisStringCommands.SetOption.upsert());
} else {
connection.set(key, value);
}
return "OK";
});
}
@Override
public byte[] get(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
return (byte[])this.execute(name, (connection) -> {
return connection.get(key);
});
}
@Override
public byte[] putIfAbsent(String name, byte[] key, byte[] value, @Nullable Duration ttl) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
Assert.notNull(value, "Value must not be null!");
return (byte[])this.execute(name, (connection) -> {
if (this.isLockingCacheWriter()) {
this.doLock(name, connection);
}
Object var6;
try {
if (!connection.setNX(key, value)) {
byte[] var10 = connection.get(key);
return var10;
}
if (shouldExpireWithin(ttl)) {
connection.pExpire(key, ttl.toMillis());
}
var6 = null;
} finally {
if (this.isLockingCacheWriter()) {
this.doUnlock(name, connection);
}
}
return (byte[])var6;
});
}
@Override
public void remove(String name, byte[] key) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(key, "Key must not be null!");
this.execute(name, (connection) -> {
return connection.del(new byte[][]{key});
});
}
@Override
public void clean(String name, byte[] pattern) {
Assert.notNull(name, "Name must not be null!");
Assert.notNull(pattern, "Pattern must not be null!");
this.execute(name, (connection) -> {
boolean wasLocked = false;
try {
if (this.isLockingCacheWriter()) {
this.doLock(name, connection);
wasLocked = true;
}
byte[][] keys = (byte[][])((Set) Optional.ofNullable(connection.keys(pattern)).orElse(Collections.emptySet())).toArray(new byte[0][]);
if (keys.length > 0) {
connection.del(keys);
}
} finally {
if (wasLocked && this.isLockingCacheWriter()) {
this.doUnlock(name, connection);
}
}
return "OK";
});
}
void lock(String name) {
this.execute(name, (connection) -> {
return this.doLock(name, connection);
});
}
void unlock(String name) {
this.executeLockFree((connection) -> {
this.doUnlock(name, connection);
});
}
private Boolean doLock(String name, RedisConnection connection) {
return connection.setNX(createCacheLockKey(name), new byte[0]);
}
private Long doUnlock(String name, RedisConnection connection) {
return connection.del(new byte[][]{createCacheLockKey(name)});
}
boolean doCheckLock(String name, RedisConnection connection) {
return connection.exists(createCacheLockKey(name));
}
private boolean isLockingCacheWriter() {
return !this.sleepTime.isZero() && !this.sleepTime.isNegative();
}
private <T> T execute(String name, Function<RedisConnection, T> callback) {
RedisConnection connection = this.connectionFactory.getConnection();
Object var4;
try {
this.checkAndPotentiallyWaitUntilUnlocked(name, connection);
var4 = callback.apply(connection);
} finally {
connection.close();
}
return (T) var4;
}
private void executeLockFree(Consumer<RedisConnection> callback) {
RedisConnection connection = this.connectionFactory.getConnection();
try {
callback.accept(connection);
} finally {
connection.close();
}
}
private void checkAndPotentiallyWaitUntilUnlocked(String name, RedisConnection connection) {
if (this.isLockingCacheWriter()) {
try {
while(this.doCheckLock(name, connection)) {
Thread.sleep(this.sleepTime.toMillis());
}
} catch (InterruptedException var4) {
Thread.currentThread().interrupt();
throw new PessimisticLockingFailureException(String.format("Interrupted while waiting to unlock cache %s", name), var4);
}
}
}
private static boolean shouldExpireWithin(@Nullable Duration ttl) {
return ttl != null && !ttl.isZero() && !ttl.isNegative();
}
private static byte[] createCacheLockKey(String name) {
return (name + "~lock").getBytes(StandardCharsets.UTF_8);
}
}
RedisConfig类
package www.gl.com.cache.cache.redis.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import www.gl.com.cache.cache.redis.bean.CustomeRedisCacheWriter;
import java.time.Duration;
@Configuration
@ConditionalOnProperty(prefix = "spring.custom-manager",name="isOpen-custom-cache",havingValue = "true")
@ConditionalOnExpression(value = "'${spring.custom-manager.cache-type}'== 'redis'|| '${spring.custom-manager.cache-type}'=='caffeine-redis'")
@EnableConfigurationProperties(RedisProperties.class)
public class RedisConfig{
static{
System.out.println("RedisConfig被创建");
}
@Bean
public CustomeRedisCacheWriter customeRedisCacheWriter(RedisConnectionFactory connectionFactory){
return new CustomeRedisCacheWriter(connectionFactory);
}
@Bean
public RedisCacheConfiguration redisCacheConfiguration(){
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
return setSerializer(redisCacheConfiguration);
}
@Bean
public RedisCacheManager redisCacheManager(CustomeRedisCacheWriter customeRedisCacheWriter, RedisCacheConfiguration redisCacheConfiguration) {
System.out.println("redisCacheManager被创建");
redisCacheConfiguration = redisCacheConfiguration
.entryTtl(Duration.ofSeconds(1000))//有效期
.disableCachingNullValues();//不缓存空值
RedisCacheManager redisCacheManager = new RedisCacheManager(customeRedisCacheWriter,redisCacheConfiguration);
return redisCacheManager;
}
private RedisCacheConfiguration setSerializer(RedisCacheConfiguration redisCacheConfiguration) {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
StringRedisSerializer stringRedisSerializer =new StringRedisSerializer();
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
redisCacheConfiguration = redisCacheConfiguration.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer));
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
return redisCacheConfiguration;
}
}
五:Caffeine
没用到
package www.gl.com.cache.cache.caffeine.bean;
import java.time.Duration;
public class CustomCaffeineCacheConfiguration{
private final Duration ttl;
private final Integer maximumSize;
private final Long expireAfterAccess;
public CustomCaffeineCacheConfiguration(Duration ttl, Integer maximumSize, Long expireAfterAccess){
this.ttl=ttl;
this.maximumSize=maximumSize;
this.expireAfterAccess=expireAfterAccess;
}
public static CustomCaffeineCacheConfiguration createDefaultCustomCacheConfiguration(){
return new CustomCaffeineCacheConfiguration(Duration.ZERO,500,600L);
}
}
CaffeineConfig类
package www.gl.com.cache.cache.caffeine.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnProperty(prefix = "spring.custom-manager",name="isOpen-custom-cache",havingValue = "true")
@ConditionalOnExpression(value = "'${spring.custom-manager.cache-type}'== 'caffeine'|| '${spring.custom-manager.cache-type}'=='caffeine-redis'")
public class CaffeineConfig {
@Bean
public CaffeineCacheManager caffeineCacheManager(){
System.out.println("caffeineCacheManager被创建");
return new CaffeineCacheManager();
}
}
六:CaffeineRedis
CustomCachingConfigurer类
package www.gl.com.cache.cache.CaffeineRedis.bean;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
public class CustomCachingConfigurer implements CachingConfigurer {
private CacheManager cacheManager;
private CacheResolver cacheResolver;
private CacheErrorHandler cacheErrorHandler;
private KeyGenerator keyGenerator;
@Override
public CacheManager cacheManager() {
return this.cacheManager;
}
@Override
public CacheResolver cacheResolver() {
return this.cacheResolver;
}
@Override
public KeyGenerator keyGenerator() {
return this.keyGenerator;
}
@Override
public CacheErrorHandler errorHandler() {
return this.cacheErrorHandler;
}
public CacheManager getCacheManager() {
return cacheManager;
}
public void setCacheManager(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
public CacheResolver getCacheResolver() {
return cacheResolver;
}
public void setCacheResolver(CacheResolver cacheResolver) {
this.cacheResolver = cacheResolver;
}
public CacheErrorHandler getCacheErrorHandler() {
return cacheErrorHandler;
}
public void setCacheErrorHandler(CacheErrorHandler cacheErrorHandler) {
this.cacheErrorHandler = cacheErrorHandler;
}
public KeyGenerator getKeyGenerator() {
return keyGenerator;
}
public void setKeyGenerator(KeyGenerator keyGenerator) {
this.keyGenerator = keyGenerator;
}
}
CustomCaffeineRedisCacheResolver类
package www.gl.com.cache.cache.CaffeineRedis.bean;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.interceptor.CacheOperationInvocationContext;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.SimpleCacheResolver;
import java.util.Collection;
public class CustomCaffeineRedisCacheResolver extends SimpleCacheResolver implements CacheResolver {
public CustomCaffeineRedisCacheResolver(CacheManager cacheManager) {
super(cacheManager);
}
}
CustomCaffeineRedisCacheContainer类
package www.gl.com.cache.cache.CaffeineRedis.bean;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.cache.Cache;
public class CustomCaffeineRedisCacheContainer {
private volatile static Map<String, Cache> cacheContainer=new ConcurrentHashMap<>();
public Map<String, Cache> getCacheContainer() {
return cacheContainer;
}
}
CustomKeyGenerator类 作用:设置缓存key(自己的定义的,需要另行设置)
package www.gl.com.cache.cache.CaffeineRedis.bean;
import org.springframework.cache.interceptor.KeyGenerator;
import java.lang.reflect.Method;
import org.springframework.util.ObjectUtils;
import www.gl.com.cache.model.common.UserModel;
public class CustomKeyGenerator implements KeyGenerator {
//Object 调用方法的对象
//Method 调用的方法
//objects 参数集合
@Override
public Object generate(Object o, Method method, Object... objects) {
String key ="";
if(!ObjectUtils.isEmpty(objects)){
if(objects[0].getClass().isAssignableFrom(UserModel.class)){
UserModel userModel = (UserModel)objects[0];
key = userModel.getUserName();
}
}else{
throw new IllegalArgumentException("key设置失败");
}
return key;
}
}
CustomCaffeineRedisCache类
package www.gl.com.cache.cache.CaffeineRedis.bean;
import org.apache.ibatis.cache.CacheException;
import org.springframework.cache.Cache;
import org.springframework.cache.support.SimpleValueWrapper;
import org.springframework.util.ObjectUtils;
import java.util.concurrent.Callable;
public class CustomCaffeineRedisCache implements Cache {
private final String name;
private final static Object lock = new Object();
private final Cache caffeineCache;
private final Cache redisCache;
private volatile Object value;
public CustomCaffeineRedisCache(String name,Cache caffeineCache,Cache redisCache){
this.name = name;
this.caffeineCache = caffeineCache;
this.redisCache = redisCache;
}
@Override
public String getName() {
return this.name;
}
@Override
public Object getNativeCache() {
return this;
}
@Override
public ValueWrapper get(Object key) {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
//一级缓存获取值
value = caffeineCache.get(key);
//如果一级缓存没有该值,降低redis访问压力
if(ObjectUtils.isEmpty(value)){
synchronized (lock){
value = caffeineCache.get(key);
if(ObjectUtils.isEmpty(value)){
value = redisCache.get(key);
caffeineCache.put(key,value);
}
}
}
}else if(!ObjectUtils.isEmpty(caffeineCache)){
value = caffeineCache.get(key);
}else if(!ObjectUtils.isEmpty(redisCache)){
value = redisCache.get(key);
}else{
throw new CacheException("Cache is null");
}
return (ValueWrapper) value;
}
@Override
public <T> T get(Object key, Class<T> aClass) {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
//一级缓存获取值
value = caffeineCache.get(key,aClass);
//如果一级缓存没有该值,降低redis访问压力
if(ObjectUtils.isEmpty(value)){
synchronized (lock){
value = caffeineCache.get(key);
if(ObjectUtils.isEmpty(value)){
value = redisCache.get(key,aClass);
caffeineCache.put(key,value);
}
}
}
}else{
if(!ObjectUtils.isEmpty(caffeineCache)){
value = caffeineCache.get(key);
}else{
value = redisCache.get(key);
}
}
return (T)value;
}
@Override
public synchronized <T> T get(Object key, Callable<T> valueLoader) {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
//一级缓存获取值
value = caffeineCache.get(key);
//如果一级缓存没有该值,降低redis访问压力
if(ObjectUtils.isEmpty(value)){
value = redisCache.get(key,valueLoader);
redisCache.put(key,value);
caffeineCache.put(key,value);
return (T) value;
}else{
return (T) ((ValueWrapper)value).get();
}
}else{
if(!ObjectUtils.isEmpty(caffeineCache)){
value = caffeineCache.get(key,valueLoader);
caffeineCache.put(key,value);
return (T) value;
}else{
value = redisCache.get(key,valueLoader);
redisCache.put(key,value);
return (T)value;
}
}
}
@Override
public void put(Object key, Object value) {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
caffeineCache.put(key,value);
redisCache.put(key,value);
}else if(!ObjectUtils.isEmpty(caffeineCache)){
caffeineCache.put(key,value);
}else if(!ObjectUtils.isEmpty(redisCache)){
redisCache.put(key,value);
}
}
@Override
public ValueWrapper putIfAbsent(Object key, Object value) {
caffeineCache.put(key,value);
redisCache.put(key,value);
return new SimpleValueWrapper(value);
}
@Override
public void evict(Object key) {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
//先删除二级缓存
redisCache.evict(key);
caffeineCache.evict(key);
}else if(!ObjectUtils.isEmpty(caffeineCache)){
caffeineCache.evict(key);
}else if(!ObjectUtils.isEmpty(redisCache)){
redisCache.evict(key);
}
}
@Override
public boolean evictIfPresent(Object key) {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
redisCache.evictIfPresent(key);
return caffeineCache.evictIfPresent(key);
}else if(!ObjectUtils.isEmpty(caffeineCache)){
return caffeineCache.evictIfPresent(key);
}else if(!ObjectUtils.isEmpty(redisCache)){
return redisCache.evictIfPresent(key);
}else {
throw new CacheException("无可用缓存");
}
}
@Override
public void clear() {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
redisCache.clear();
caffeineCache.clear();
}else if(!ObjectUtils.isEmpty(caffeineCache)){
caffeineCache.clear();
}else if(!ObjectUtils.isEmpty(redisCache)){
redisCache.clear();
}
}
@Override
public boolean invalidate() {
if(!ObjectUtils.isEmpty(caffeineCache)&&!ObjectUtils.isEmpty(redisCache)){
redisCache.invalidate();
return caffeineCache.invalidate();
}else if(!ObjectUtils.isEmpty(caffeineCache)){
return caffeineCache.invalidate();
}else if(!ObjectUtils.isEmpty(redisCache)){
return redisCache.invalidate();
}
return false;
}
}
CustomCaffeineRedisManager类
package www.gl.com.cache.cache.CaffeineRedis.bean;
import java.util.stream.Collectors;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import java.util.Collection;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.util.ObjectUtils;
public class CustomCaffeineRedisManager implements CacheManager {
private final CaffeineCacheManager caffeineCacheManager;
private final RedisCacheManager redisCacheManager;
private final static CustomCaffeineRedisCacheContainer customCaffeineRedisCacheContainer=new CustomCaffeineRedisCacheContainer();
public CustomCaffeineRedisManager(CaffeineCacheManager caffeineCacheManager,RedisCacheManager redisCacheManager){
this.caffeineCacheManager = caffeineCacheManager;
this.redisCacheManager = redisCacheManager;
}
@Override
public Cache getCache(String name) {
Cache cache = this.customCaffeineRedisCacheContainer.getCacheContainer().get(name);
if (cache == null) {
synchronized (this.customCaffeineRedisCacheContainer) {
cache = this.customCaffeineRedisCacheContainer.getCacheContainer().get(name);
if (cache == null) {
cache = createCache(name);
this.customCaffeineRedisCacheContainer.getCacheContainer().put(name,cache);
}
}
}
return cache;
}
public Cache createCache(String name){
if(!ObjectUtils.isEmpty(caffeineCacheManager)&&!ObjectUtils.isEmpty(redisCacheManager)){
return new CustomCaffeineRedisCache(name,caffeineCacheManager.getCache(name),redisCacheManager.getCache(name));
} else if(ObjectUtils.isEmpty(caffeineCacheManager)){
return new CustomCaffeineRedisCache(name,null,redisCacheManager.getCache(name));
}else if(ObjectUtils.isEmpty(redisCacheManager)){
return new CustomCaffeineRedisCache(name,caffeineCacheManager.getCache(name),null);
}else{
return new CustomCaffeineRedisCache(name,null,null);
}
}
@Override
public Collection<String> getCacheNames() {
return customCaffeineRedisCacheContainer
.getCacheContainer()
.entrySet()
.stream()
.collect(Collectors.mapping(item->item.getKey(),Collectors.toList()));
}
}
CaffeineRedisConfig类
package www.gl.com.cache.cache.CaffeineRedis.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import www.gl.com.cache.cache.CaffeineRedis.bean.CustomCachingConfigurer;
import www.gl.com.cache.cache.CaffeineRedis.bean.CustomCaffeineRedisCacheResolver;
import www.gl.com.cache.cache.CaffeineRedis.bean.CustomCaffeineRedisManager;
import www.gl.com.cache.cache.CaffeineRedis.bean.CustomKeyGenerator;
@Configuration
@ConditionalOnProperty(prefix = "spring.custom-manager",name="isOpen-custom-cache",havingValue = "true")
@EnableCaching
public class CaffeineRedisConfig{
@Bean
public CustomKeyGenerator customKeyGenerator() {
return new CustomKeyGenerator();
}
//选择使用redisCacheManager还是CaffeineCacheManager
@Bean
public CustomCaffeineRedisCacheResolver customCaffeineRedisCacheResolver(@Qualifier(value = "customCaffeineRedisManager") CustomCaffeineRedisManager cacheManager){
System.out.println("打印manager");
return new CustomCaffeineRedisCacheResolver(cacheManager);
}
// @Bean
// public CustomCaffeineRedisCacheResolver customCaffeineRedisCacheResolver(@Qualifier(value = "redisCacheManager") RedisCacheManager cacheManager){
// System.out.println("打印manager");
// return new CustomCaffeineRedisCacheResolver(cacheManager);
// }
@Bean("customCaffeineRedisManager")
public CustomCaffeineRedisManager customCaffeineRedisManager( @Autowired(
required = false
)RedisCacheManager redisCacheManager, @Autowired(
required = false
) CaffeineCacheManager caffeineCacheManager){
System.out.println("创建manager");
return new CustomCaffeineRedisManager(caffeineCacheManager,redisCacheManager);
}
@Bean
public CustomCachingConfigurer customCachingConfigurer(CustomCaffeineRedisCacheResolver customCaffeineRedisCacheResolver,
CustomKeyGenerator customKeyGenerator){
CustomCachingConfigurer customCachingConfigurer = new CustomCachingConfigurer();
//设置默认的CacheManager
customCachingConfigurer.setCacheManager(new CaffeineCacheManager());
customCachingConfigurer.setCacheResolver(customCaffeineRedisCacheResolver);
customCachingConfigurer.setKeyGenerator(customKeyGenerator);
return customCachingConfigurer;
}
}
七:测试
MyRedisService类
package www.gl.com.cache.service.redis;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.springframework.cache.annotation.*;
import org.springframework.stereotype.Service;
import www.gl.com.cache.model.common.UserModel;
@Service
@CacheConfig(cacheNames = "user")
public class MyRedisService {
public UserModel getUserModelByName(String name){
return new HashMap<Integer,String>(){
{
put(1,"zhangsan");
put(2,"lisi");
put(3,"wanger");
}
}.entrySet()
.stream()
.map(entry->{
UserModel userModel = new UserModel();
userModel.setUserId(entry.getKey());
userModel.setUserName(entry.getValue());
return userModel;
}).collect(Collectors.toList())
.stream()
.filter(item->{ return name.equals(item.getUserName()); })
.findFirst()
.get();
};
//@Cacheable(key = "#root.caches[0].name")
@Cacheable
public UserModel get(UserModel userModel){
return getUserModelByName(userModel.getUserName());
}
@CacheEvict
public void delete(UserModel userModel){
}
@CachePut
public UserModel update(UserModel userModel){
return userModel;
}
}
Test类
package www.gl.com.cache;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import www.gl.com.cache.model.common.UserModel;
import www.gl.com.cache.service.redis.MyRedisService;
import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Unit test for simple App.
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class AppTest {
@Resource
private MyRedisService myredisService;
/**
* Rigorous Test :-)
*/
@Test
public void shouldAnswerWithTrue() throws InterruptedException {
myredisService.get("zhangsan");
UserModel userModel =new UserModel();
userModel.setUserName("zhangsan");
userModel.setUserId(2);
myredisService.update(userModel);
System.out.println(myredisService.get("zhangsan"));
}
}
测试结果:
八:依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>www.gl.com</groupId>
<artifactId>myredis02</artifactId>
<version>1.0-SNAPSHOT</version>
<name>myredis02</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.3.1.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<!-- Druid 数据连接池依赖 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.13</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>8.0.11</version>
</dependency>
<!-- fast json -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.44</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-pool2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
<version>2.3.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.ben-manes.caffeine/caffeine -->
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.8.5</version>
</dependency>
</dependencies>
<profiles>
<!-- 开发环境 -->
<profile>
<id>dev</id>
<properties>
<spring.profiles.active>dev</spring.profiles.active>
</properties>
<!-- 设置当前环境为默认环境 -->
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<!-- 测试环境 -->
<profile>
<id>test</id>
<properties>
<spring.profiles.active>test</spring.profiles.active>
</properties>
</profile>
<!-- 生产环境 -->
<profile>
<id>prod</id>
<properties>
<spring.profiles.active>prod</spring.profiles.active>
</properties>
</profile>
</profiles>
</project>