本文主要是介绍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 实现二级缓存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!