Caffeine+redis 实现二级缓存

2024-02-15 01:38

本文主要是介绍Caffeine+redis 实现二级缓存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一:目录结构

在这里插入图片描述

二:分而治之

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: redisredis:database: 0host: *******port: 6379password: 123456
#    jedis:
#      pool:
#        #连接池最大连接数
#        max-active: 8
#        #连接池最大阻塞等待时间
#        max-wait: -1
#        #连接池最大空闲连接数
#        max-idle: 500
#        #连接池最小空闲连接数
#        min-idle: 0lettuce:pool:max-wait: -1max-idle: 8min-idle: 0max-active: 8shutdown-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;}@Overridepublic 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";});}@Overridepublic 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);});}@Overridepublic 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;});}@Overridepublic 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});});}@Overridepublic 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被创建");}@Beanpublic CustomeRedisCacheWriter customeRedisCacheWriter(RedisConnectionFactory connectionFactory){return new CustomeRedisCacheWriter(connectionFactory);}@Beanpublic RedisCacheConfiguration redisCacheConfiguration(){RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();return setSerializer(redisCacheConfiguration);}@Beanpublic 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

   CustomCaffeineCacheConfiguration类,没用到

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 {@Beanpublic 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;@Overridepublic CacheManager cacheManager() {return this.cacheManager;}@Overridepublic CacheResolver cacheResolver() {return this.cacheResolver;}@Overridepublic KeyGenerator keyGenerator() {return this.keyGenerator;}@Overridepublic 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 参数集合@Overridepublic 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;}@Overridepublic String getName() {return this.name;}@Overridepublic Object getNativeCache() {return this;}@Overridepublic 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;}@Overridepublic <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;}@Overridepublic 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;}}}@Overridepublic 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);}}@Overridepublic ValueWrapper putIfAbsent(Object key, Object value) {caffeineCache.put(key,value);redisCache.put(key,value);return new SimpleValueWrapper(value);}@Overridepublic 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);}}@Overridepublic 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("无可用缓存");}}@Overridepublic 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();}}@Overridepublic 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;}@Overridepublic 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);}}@Overridepublic 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{@Beanpublic CustomKeyGenerator customKeyGenerator() {return new CustomKeyGenerator();}//选择使用redisCacheManager还是CaffeineCacheManager@Beanpublic 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);}@Beanpublic CustomCachingConfigurer customCachingConfigurer(CustomCaffeineRedisCacheResolver customCaffeineRedisCacheResolver,CustomKeyGenerator customKeyGenerator){CustomCachingConfigurer customCachingConfigurer =  new CustomCachingConfigurer();//设置默认的CacheManagercustomCachingConfigurer.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")@Cacheablepublic UserModel get(UserModel userModel){return getUserModelByName(userModel.getUserName());}@CacheEvictpublic void delete(UserModel userModel){}@CachePutpublic 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 {@Resourceprivate MyRedisService myredisService;/*** Rigorous Test :-)*/@Testpublic 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>

这篇关于Caffeine+redis 实现二级缓存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/710118

相关文章

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

让树莓派智能语音助手实现定时提醒功能

最初的时候是想直接在rasa 的chatbot上实现,因为rasa本身是带有remindschedule模块的。不过经过一番折腾后,忽然发现,chatbot上实现的定时,语音助手不一定会有响应。因为,我目前语音助手的代码设置了长时间无应答会结束对话,这样一来,chatbot定时提醒的触发就不会被语音助手获悉。那怎么让语音助手也具有定时提醒功能呢? 我最后选择的方法是用threading.Time

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略

Kubernetes PodSecurityPolicy:PSP能实现的5种主要安全策略 1. 特权模式限制2. 宿主机资源隔离3. 用户和组管理4. 权限提升控制5. SELinux配置 💖The Begin💖点点关注,收藏不迷路💖 Kubernetes的PodSecurityPolicy(PSP)是一个关键的安全特性,它在Pod创建之前实施安全策略,确保P

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

C++——stack、queue的实现及deque的介绍

目录 1.stack与queue的实现 1.1stack的实现  1.2 queue的实现 2.重温vector、list、stack、queue的介绍 2.1 STL标准库中stack和queue的底层结构  3.deque的简单介绍 3.1为什么选择deque作为stack和queue的底层默认容器  3.2 STL中对stack与queue的模拟实现 ①stack模拟实现