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

相关文章

Vue ElementUI中Upload组件批量上传的实现代码

《VueElementUI中Upload组件批量上传的实现代码》ElementUI中Upload组件批量上传通过获取upload组件的DOM、文件、上传地址和数据,封装uploadFiles方法,使... ElementUI中Upload组件如何批量上传首先就是upload组件 <el-upl

Docker部署Jenkins持续集成(CI)工具的实现

《Docker部署Jenkins持续集成(CI)工具的实现》Jenkins是一个流行的开源自动化工具,广泛应用于持续集成(CI)和持续交付(CD)的环境中,本文介绍了使用Docker部署Jenkins... 目录前言一、准备工作二、设置变量和目录结构三、配置 docker 权限和网络四、启动 Jenkins

Python3脚本实现Excel与TXT的智能转换

《Python3脚本实现Excel与TXT的智能转换》在数据处理的日常工作中,我们经常需要将Excel中的结构化数据转换为其他格式,本文将使用Python3实现Excel与TXT的智能转换,需要的可以... 目录场景应用:为什么需要这种转换技术解析:代码实现详解核心代码展示改进点说明实战演练:从Excel到

如何使用CSS3实现波浪式图片墙

《如何使用CSS3实现波浪式图片墙》:本文主要介绍了如何使用CSS3的transform属性和动画技巧实现波浪式图片墙,通过设置图片的垂直偏移量,并使用动画使其周期性地改变位置,可以创建出动态且具有波浪效果的图片墙,同时,还强调了响应式设计的重要性,以确保图片墙在不同设备上都能良好显示,详细内容请阅读本文,希望能对你有所帮助...

C# string转unicode字符的实现

《C#string转unicode字符的实现》本文主要介绍了C#string转unicode字符的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随... 目录1. 获取字符串中每个字符的 Unicode 值示例代码:输出:2. 将 Unicode 值格式化

python安装whl包并解决依赖关系的实现

《python安装whl包并解决依赖关系的实现》本文主要介绍了python安装whl包并解决依赖关系的实现,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录一、什么是whl文件?二、我们为什么需要使用whl文件来安装python库?三、我们应该去哪儿下

Python脚本实现图片文件批量命名

《Python脚本实现图片文件批量命名》这篇文章主要为大家详细介绍了一个用python第三方库pillow写的批量处理图片命名的脚本,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录前言源码批量处理图片尺寸脚本源码GUI界面源码打包成.exe可执行文件前言本文介绍一个用python第三方库pi

Java中将异步调用转为同步的五种实现方法

《Java中将异步调用转为同步的五种实现方法》本文介绍了将异步调用转为同步阻塞模式的五种方法:wait/notify、ReentrantLock+Condition、Future、CountDownL... 目录异步与同步的核心区别方法一:使用wait/notify + synchronized代码示例关键

Nginx实现动态封禁IP的步骤指南

《Nginx实现动态封禁IP的步骤指南》在日常的生产环境中,网站可能会遭遇恶意请求、DDoS攻击或其他有害的访问行为,为了应对这些情况,动态封禁IP是一项十分重要的安全策略,本篇博客将介绍如何通过NG... 目录1、简述2、实现方式3、使用 fail2ban 动态封禁3.1 安装 fail2ban3.2 配

Java中实现订单超时自动取消功能(最新推荐)

《Java中实现订单超时自动取消功能(最新推荐)》本文介绍了Java中实现订单超时自动取消功能的几种方法,包括定时任务、JDK延迟队列、Redis过期监听、Redisson分布式延迟队列、Rocket... 目录1、定时任务2、JDK延迟队列 DelayQueue(1)定义实现Delayed接口的实体类 (