SpringBoot 缓存
在Spring Boot中通过@EnableCaching注解自动化配置合适的缓存管理器。当我们不指定具体其他第三方实现的时候,Spring Boot的Cache模块会使用ConcurrentHashMap来存储。而实际生产使用的时候,因为我们可能需要更多其他特性,往往就会采用其他缓存框架,所以接下来介绍常用缓存的整合与使用。
1、引入缓存
第一步:在pom.xml中引入cache依赖,添加如下内容:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
第二步:pom.xml中增加相关依赖::在Spring Boot主类中增加@EnableCaching注解开启缓存功能,如下:
@EnableCaching
@SpringBootApplication
public class Chapter51Application {
public static void main(String[] args) {
SpringApplication.run(Chapter51Application.class, args);
}
}
第三步:pom.xml中增加相关依赖::在数据访问接口中,增加缓存配置注解,如:
public interface UserService extends BaseService<User>{
/**
* 获取用户列表
* @param name 名称
* @param age 年龄
* @return
*/
@Cacheable(cacheNames = "test", key = "#name+'_'+#age")
List<User> listUser(String name, Integer age);
}
第四步:执行请求,可以在控制台中输出了下面的内容
2021-12-08 10:26:18.821 TRACE 43986 --- [nio-8888-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.cloud.controller.UserController#getUserList(User)
CacheManager type : class org.springframework.cache.concurrent.ConcurrentMapCacheManager
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where (user0_.name=? or ''=?) and (user0_.age=? or ? is null) order by user0_.id
2021-12-08 10:26:18.821 TRACE 43986 --- [nio-8888-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.cloud.controller.UserController#getUserList(User)
CacheManager type : class org.springframework.cache.concurrent.ConcurrentMapCacheManager
到这里,我们可以看到,在调用第二次listUser函数时,没有再执行select语句,也就直接减少了一次数据库的读取操作。
关于@Cacheable相关详细配置,可自行百度
@Cacheable注解
@Cacheable注解也是有Spring框架提供的,可以作用域类或者方法上(通常用在数据查询方法上),用于对方法结果进行缓存存储。
@Cacheable注解执行顺序是,先进行缓存查询,如果为空进行方法查询,并将结果进行缓存;如果缓存中有数据,不进行方法查询,直接使用缓存数据。
| 属性名 | 说明 |
|---|---|
| value/cacheNames | 指定缓存空间的名称,必配属性。两个属性二选一使用 |
| key | 指定缓存数据的key,默认使用方法参数值,可以使用SpEL表达式 |
| keyGenerator | 指定缓存数据的key的生成器,与key属性二选一使用 |
| cacheManager | 指定缓存管理器 |
| cacheResolver | 指定缓存解析器,与cacheManager属性二选一使用 |
| condition | 指定在符合某条件下,进行数据缓存 |
| unless | 指定在符合某条件下,不进行数据缓存 |
| sync | 指定是否使用异步缓存,默认为false |
@CachePut注解
@CachePut注解有Spring框架提供,可以用于类或者方法上(通常用在数据更新方法上),该注解的作用是更新缓存数据。@CachePut注解的执行顺序是,先进行方法调用,然后将方法结果更新到缓存中。
@CachePut注解也提供了和@Cacheable相同的注解属性。
@CacheEvict注解
@CacheEvict注解有Spring框架提供,可以用于类或者方法上(通常用在数据删除方法上),该注解的作用是删除缓存数据。@CacheEvict注解的执行顺序是,先进行方法调用,然后将缓存进行删除。
@CacheEvict注解除了拥有和@Cacheable相同的注解属性外,还额外提供了两个特殊注解allEntries和beforeInvocation。
| 属性名 | 说明 |
|---|---|
| allEntries | 表示是否清除指定缓存控件的所有缓存数据,默认为false |
| beforeInvocation | 表示是否在方法执行前进行缓存清除,默认为false |
@Caching注解
@Caching注解用于针对复杂规则的数据缓存管理,可以用于类或者方法,在@Caching注解内部包含Cacheable、put、evict三个属性,分别对应于@Cacheable、@CachePut、@CacheEVict三个注解。
@CacheConfig注解
@CacheConfig注解使用在类上,主要用于统筹管理类中所有使用@Cacheable、@CachePut、@CacheEvict注解标注方法中的公共属性,这型公共属性包括cacheNames、keyGeneragor、cacheManager、cacheResolver。
2、使用EhCache缓存
2-1 快速集成
第一步:在pom.xml中引入ehcache依赖
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
第二步:在src/main/resources/cache目录下创建:ehcache-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://ehcache.org/ehcache.xsd"
updateCheck="false">
<!--
name:缓存名称。
maxElementsInMemory:缓存最大个数。
eternal:对象是否永久有效,一但设置了,timeout将不起作用。
timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。
timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。
overflowToDisk:当内存中对象数量达到maxElementsInMemory时,Ehcache将会对象写到磁盘中。
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。
maxElementsOnDisk:硬盘最大缓存个数。
diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。
clearOnFlush:内存数量最大时是否清除。
-->
<diskStore path="java.io.tmpdir"/>
<!-- 默认缓存 -->
<defaultCache name="defaultCache"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="600"
overflowToDisk="false"
maxElementsOnDisk="100000"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
<!-- 系统缓存 -->
<cache name="sysCache"
maxElementsInMemory="10000"
maxElementsOnDisk="100000"
eternal="false"
timeToIdleSeconds="86400"
timeToLiveSeconds="86400"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
memoryStoreEvictionPolicy="LRU"/>
</ehcache>
第三步:在application.properties配置如下
##ehcache
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:cache/ehcache-spring.xml
第四步:执行请求,可以在控制台中输出了下面的内容
2021-12-08 10:26:18.821 TRACE 43986 --- [nio-8888-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.cloud.controller.UserController#getUserList(User)
CacheManager type : class org.springframework.cache.ehcache.EhCacheCacheManager
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where (user0_.name=? or ''=?) and (user0_.age=? or ? is null) order by user0_.id
2021-12-08 10:27:20.486 TRACE 43986 --- [nio-8888-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.cloud.controller.UserController#getUserList(User)
CacheManager type : class org.springframework.cache.ehcache.EhCacheCacheManager
可以看到:
- 第一行输出的CacheManager type为
org.springframework.cache.ehcache.EhCacheCacheManager,而不是上一篇中的ConcurrentHashMap了。 - 第二次查询的时候,没有输出SQL语句,所以是走的缓存获取
2-2 EhCache配置类
/**
* @title EhCacheConfig
* @description EhCache配置类
* @author zxkxc
* @date 2023年02月06日
*/
@Configuration
@EnableCaching
public class EhCacheConfig extends CachingConfigurerSupport {
/**
* EhCache的配置
*/
@Bean
public EhCacheCacheManager cacheManager(CacheManager cacheManager) {
return new EhCacheCacheManager(cacheManager);
}
/**
* EhCache的配置
*/
@Bean
public EhCacheManagerFactoryBean ehcache() {
EhCacheManagerFactoryBean ehCacheManagerFactoryBean = new EhCacheManagerFactoryBean();
ehCacheManagerFactoryBean.setConfigLocation(new ClassPathResource("cache/ehcache-spring.xml"));
return ehCacheManagerFactoryBean;
}
}
2-3 EhCache工具类
/**
* @title EhcacheUtil
* @description Ehcache缓存工具类
* @author zxkxc
* @date 2023年02月06日
*/
@Slf4j
@Component
public class EhcacheUtil {
public final CacheManager cacheManager;
public EhcacheUtil(CacheManager cacheManager) {
this.cacheManager = cacheManager;
}
/**
* 获取Cache类
* @param cacheName 缓存名称
* @return 缓存类
*/
public Cache getCache(String cacheName) {
return cacheManager.getCache(cacheName);
}
/**
* 创建Cache类
* @param cacheName 缓存名称
* @return 缓存类
*/
public Cache createCache(String cacheName) {
if (!cacheManager.cacheExists(cacheName)) {
Cache cache = new Cache(cacheName, 10000, false, true, Integer.MAX_VALUE, Integer.MAX_VALUE);
cacheManager.addCache(cache);
}
return cacheManager.getCache(cacheName);
}
/**
* 添加缓存数据
* @param cacheName 缓存名称
* @param key 缓存键值
* @param value 缓存数据
*/
public void put(String cacheName, String key, Object value) {
try {
Cache cache = cacheManager.getCache(cacheName);
Element element = new Element(key, value);
cache.put(element);
} catch (Exception e) {
e.printStackTrace();
log.error("添加缓存失败:{}",e.getMessage());
}
}
/**
* 添加缓存数据
* @param cacheName 缓存名称
* @param key 缓存键值
* @param value 缓存数据
* @param eternal 是否永久有效
* @param time 有效时长(单位:秒)
*/
public void put(String cacheName, String key, Object value, boolean eternal, int time) {
try {
Cache cache = cacheManager.getCache(cacheName);
Element element = new Element(key, value);
element.setEternal(eternal);
element.setTimeToLive(time);
cache.put(element);
} catch (Exception e) {
e.printStackTrace();
log.error("添加缓存失败:{}",e.getMessage());
}
}
/**
* 获取缓存数据
* @param cacheName 缓存名称
* @param key 缓存键值
* @return 缓存数据
*/
public Object get(String cacheName, String key) {
try {
Cache cache = cacheManager.getCache(cacheName);
Element element = cache.get(key);
return element == null ? null : element.getObjectValue();
} catch (Exception e) {
e.printStackTrace();
log.error("获取缓存数据失败:{}",e.getMessage());
return null;
}
}
/**
* 删除缓存数据
* @param cacheName 缓存名称
* @param key 缓存键值
*/
public void delete(String cacheName, String key) {
try {
Cache cache = cacheManager.getCache(cacheName);
cache.remove(key);
} catch (Exception e) {
e.printStackTrace();
log.error("删除缓存数据失败:{}",e.getMessage());
}
}
}
3、使用Redis缓存
虽然EhCache已经能够适用很多应用场景,但是由于EhCache是进程内的缓存框架,在集群模式下时,各应用服务器之间的缓存都是独立的,因此在不同服务器的进程间会存在缓存不一致的情况。即使EhCache提供了集群环境下的缓存同步策略,但是同步依然是需要一定的时间,短暂的缓存不一致依然存在。
在一些要求高一致性(任何数据变化都能及时的被查询到)的系统和应用中,就不能再使用EhCache来解决了,这个时候使用集中式缓存就可以很好的解决缓存数据的一致性问题。接下来看看如何在Spring Boot的缓存支持中使用Redis实现数据缓存。
3-1、快速集成
第一步:pom.xml中增加相关依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
第二步:配置文件中增加配置信息,以本地运行为例,比如:
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.lettuce.pool.max-idle=8
spring.redis.lettuce.pool.max-active=8
spring.redis.lettuce.pool.max-wait=-1ms
spring.redis.lettuce.pool.min-idle=0
spring.redis.lettuce.shutdown-timeout=100ms
关于连接池的配置,注意几点:
- Redis的连接池配置在1.x版本中前缀为
spring.redis.pool与Spring Boot 2.x有所不同。- 在1.x版本中采用jedis作为连接池,而在2.x版本中采用了lettuce作为连接池
- 以上配置均为默认值,实际上生产需进一步根据部署情况与业务要求做适当修改.
第三步:执行请求,可以在控制台中输出了下面的内容
2021-12-08 10:32:23.483 TRACE 44087 --- [nio-8888-exec-1] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.cloud.controller.UserController#getUserList(User)
CacheManager type : class org.springframework.data.redis.cache.RedisCacheManager
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.name as name3_0_ from user user0_ where (user0_.name=? or ''=?) and (user0_.age=? or ? is null) order by user0_.id
2021-12-08 10:32:25.535 TRACE 44087 --- [nio-8888-exec-2] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.cloud.controller.UserController#getUserList(User)
CacheManager type : class org.springframework.data.redis.cache.RedisCacheManager
使用redis缓存需要预先在当前本机/服务器上安装redis服务,以下大概描述下实操中在Mac中安装运行redis服务
2、解压redis-6.2.6.tar.gz,拷贝到任意目录,例如/Users/houzx/
3、执行解压命令:tar zxcf redis-6.2.6.tar.gz
4、进入/Users/houzx/redis-6.2.6目录下,执行命令
make && make install安装完成,配置都采用默认配置5、执行
src/redis-server命令启动服务,需要在redis解压目录下执行,如上述/Users/houzx/redis-6.2.6
可以看到:
- 第一行输出的CacheManager type为
org.springframework.data.redis.cache.RedisCacheManager,而不是上一篇中的EhCacheCacheManager了 - 第二次查询的时候,没有输出SQL语句,所以是走的缓存获取
3-2、Redis配置类
/**
* @title RedisConfig
* @description Redis配置类
* @author zxkxc
* @date 2022年03月06日
*/
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
private static final int DEFAULT_EXPIRE_TIME = 60 * 60 * 24;
private static final String PARAM_CACHE_NAME = "paramsCache";
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(mapper);
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(jackson2JsonRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(DEFAULT_EXPIRE_TIME))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer()))
.disableCachingNullValues();
// 配置自定义的缓存空间
Set<String> cacheNames = new HashSet<>();
cacheNames.add(PARAM_CACHE_NAME);
// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
//configMap.put(PARAM_CACHE_NAME, config.entryTtl(Duration.ofSeconds(DEFAULT_EXPIRE_TIME * 12)));
return RedisCacheManager.builder(factory)
.cacheDefaults(config)
.initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap)
.build();
}
}
3-3、RedisUtil工具类
package com.zxkxc.cloud.common.utils.cache;
import com.zxkxc.cloud.common.utils.ReflectUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
/**
* @title RedisUtil
* @description Redis缓存工具类
* @author houzx
* @date 2022年03月05日
*/
@Component
public class RedisUtil {
public final RedisTemplate redisTemplate;
public RedisUtil(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 设置有效时间
* @param key Redis键
* @param timeout 超时时间
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout) {
return timeout > 0 && expire(key, timeout, TimeUnit.SECONDS);
}
/**
* 设置有效时间
* @param key Redis键
* @param timeout 超时时间
* @param unit 时间单位
* @return true=设置成功;false=设置失败
*/
public boolean expire(final String key, final long timeout, final TimeUnit unit) {
return redisTemplate.expire(key, timeout, unit);
}
/**
* 获取缓存数据过期时间
* @param key Redis键
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断是否存在缓存数据
* @param key Redis键
* @return true:存在;false:不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 删除缓存数据
* @param key Redis键
* @return 删除结果
*/
public boolean deleteKey(String... key) {
if (key != null) {
int length = key.length;
if (length > 0) {
if (length == 1) {
return redisTemplate.delete(key[0]);
} else {
return redisTemplate.delete(CollectionUtils.arrayToList(key)) == length;
}
}
}
return false;
}
/**
* 缓存基本的对象,Integer、String、实体类等
* @param key 缓存的键值
* @param value 缓存的值
*/
public <T> void setCacheObject(final String key, final T value) {
redisTemplate.opsForValue().set(key, value);
}
/**
* 缓存基本的对象,Integer、String、实体类等
* @param key 缓存的键值
* @param value 缓存的值
* @param timeout 超时时间
* @param timeUnit 时间颗粒度
*/
public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {
redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
}
/**
* 获得缓存的基本对象。
* @param key 缓存键值
* @return 缓存键值对应的数据
*/
public <T> T getCacheObject(final String key) {
ValueOperations<String, T> operation = redisTemplate.opsForValue();
return operation.get(key);
}
/**
* 删除单个对象
* @param key 缓存键值
* @return 删除结果
*/
public boolean deleteObject(final String key) {
return redisTemplate.delete(key);
}
/**
* 删除集合对象
* @param collection 多个对象
* @return 删除数量
*/
public long deleteObject(final Collection collection) {
return redisTemplate.delete(collection);
}
/**
* 缓存List数据
* @param key 缓存的键值
* @param dataList 待缓存的List数据
* @return 缓存的对象
*/
public <T> long setCacheList(final String key, final List<T> dataList) {
Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
return count == null ? 0 : count;
}
/**
* 获得缓存的list对象
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheList(final String key) {
return redisTemplate.opsForList().range(key, 0, -1);
}
/**
* 缓存Set
* @param key 缓存键值
* @param dataSet 缓存的数据
* @return 缓存数据的对象
*/
public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet) {
BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
for (T t : dataSet) {
setOperation.add(t);
}
return setOperation;
}
/**
* 获得缓存的set
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> Set<T> getCacheSet(final String key) {
return redisTemplate.opsForSet().members(key);
}
/**
* 缓存Map
* @param key 缓存的键值
* @param dataMap 缓存的数据
*/
public <T> void setCacheMap(final String key, final Map<String, T> dataMap) {
if (dataMap != null) {
redisTemplate.opsForHash().putAll(key, dataMap);
}
}
/**
* 获得缓存的Map
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> Map<String, T> getCacheMap(final String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* 获得缓存的集合
* @param key 缓存的键值
* @return 缓存键值对应的数据
*/
public <T> List<T> getCacheObjList(final String key) {
return redisTemplate.opsForHash().values(key);
}
/**
* 往Hash中存入数据
* @param key Redis键
* @param hKey Hash键
* @param value 值
*/
public <T> void setCacheMapValue(final String key, final String hKey, final T value) {
redisTemplate.opsForHash().put(key, hKey, value);
}
/**
* 删除map中的数据
* @param key Redis键
* @param hKeys ash键
*/
public long deleteCacheMapValue(final String key, final Object...hKeys) {
return redisTemplate.opsForHash().delete(key, hKeys);
}
/**
* 获取Hash中的数据
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey) {
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
return opsForHash.get(key, hKey);
}
/**
* 获得缓存的基本对象列表
* @param key 字符串前缀
* @return 对象列表
*/
public Collection<String> getCacheMapKeys(final String key) {
return redisTemplate.opsForHash().keys(key);
}
/**
* 获取多个Hash中的数据
* @param key Redis键
* @param hKeys Hash键集合
* @return Hash对象集合
*/
public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys) {
return redisTemplate.opsForHash().multiGet(key, hKeys);
}
/**
* 获得缓存的基本对象列表
* @param pattern 字符串前缀
* @return 对象列表
*/
public Collection<String> keys(final String pattern) {
return redisTemplate.keys(pattern);
}
/**
* 获取Hash中的数据
* @param key Redis键
* @param hKey Hash键
* @return Hash中的对象
*/
public <T> T getCacheMapValue(final String key, final String hKey, Callable<T> valueLoader) {
HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
Object cacheObj = opsForHash.get(key, hKey);
Object value = null;
if (cacheObj == null) {
T call = getCallValue(valueLoader);
if(null != call){
value = call;
redisTemplate.opsForHash().put(key, hKey, value);
return(T) value;
}else{
return null;
}
} else {
return (T) cacheObj;
}
}
/**
* 动态方法执行
* @param valueLoader
* @param <T>
* @return
*/
public <T> T getCallValue(Callable<T> valueLoader) {
try {
T call = valueLoader.call();
if (ObjectUtils.isNotEmpty(call)) {
Field field = ReflectUtil.getField(call.getClass(), "id");
if (ObjectUtils.isNotEmpty(field) && ObjectUtils.isEmpty(ClassUtils.getMethod(call.getClass(), "id").invoke(call))) {
return null;
}
return call;
}
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
return null;
}
}
写在最后;
小伙伴们有什么好的方法可以同时集成Ehcache、Redis相关依赖、配置、工具,但是可以在全局配置文件中根据需要仅启用某一个缓存呢??欢迎留言~