# HOS-Cache 缓存
# 概述
缓存功能共分为两大类:HOS-Cache可切换缓存 与 Redis缓存
HOS-Cache可切换缓存组件底层兼容Ehcache
以及Redis
,
可通过配置项完成不同的缓存库无缝切换,
并提供了注解和工具类两种方式供开发人员使用,
- 注解的使用方式:提供包括@HOSCacheable,@HOSCachePut,@HOSCacheEvict, @Caching,@HOSCacheConfig在内的五种注解,并兼容多租户功能
- 工具类使用方式:提供 兼容多租户功能 与 原生功能(无特殊处理) 两种工具类, 开发人员通过调用工具类中提供的方法,完成对缓存的添加、更新、删除、设置过期时间的操作。
Redis缓存 请参考Redis使用说明
对比:HOS-Cache 与 Redis缓存 均提供工具类的使用方式,
相比Redis缓存,HOS-Cache底层兼容Ehcache
以及Redis
,
并提供注解的使用方式,另外HOS-Cache在使用时需要指定CacheName(缓存名称,为兼容Ehcache),
Redis缓存则不需要
本文主要介绍 HOS-Cache可切换缓存
# 配置
# 导入maven依赖
<dependency>
<groupId>com.mediway.hos</groupId>
<artifactId>hos-framework-cache-starter</artifactId>
</dependency>
# 配置项
本功能相关的配置项位于application-dev.yml中,具体的位置如下图:
基础配置项
framework:
hoscache:
##使用的缓存类型,目前支持 redis ehcache
type: ehcache
##缓存前缀,用于在用同一个缓存服务时区分各个系统缓存
prev: hos
通过framework.hoscache.type
配置项,指定具体使用的缓存库,目前可用的值为redis与ehcache
framework.hoscache.cacheConfigureNames
配置项中为缓存名称(cacheName)以及其过期时间等参数
原framework.hoscache.cacheConfigureNames
配置项已取消使用,现可通过缓存管理页面功能直接配置,
详情请参考 缓存管理
下面分别介绍关于Ehcahe和Redis的配置项,使用者可以根据使用的缓存库完善对应的配置项
Ehcache缓存库配置项:
framework:
hoscache:
# ehcache缓存位置
ehcachePath: /temp
Redis缓存库配置项:
spring:
redis:
password: xxx #缓存库密码
database: 0
timeout: 5000 #连接超时时间(毫秒)
#host: 127.0.0.1 #缓存库地址,单机模式下使用
#port: 6379 #缓存库使用的接口,单机模式下使用
#连接池相关配置,一般直接采用默认值,可以不写
pool:
max-activ: 8 #最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 8 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
#集群模式下的缓存库的ip和接口配置
cluster:
nodes: 192.16.18.196:7001,192.16.18.196:7002,192.16.18.196:7003,192.16.18.196:7004,192.16.18.196:7005,192.16.18.196:7006
# 功能简介
本插件包含 注解 与 工具类 两部分功能。功能介绍如下:
# 注解功能
支持 @HOSCacheConfig @HOSCacheable, @HOSCachePut, @HOSCacheEvict, @HOSCaching 五种注解。具体功能描述如下:
# @HOSCacheConfig
功能描述:
用在类上,为 @HOSCacheable、@HOSCacheEvict、@HOSCachePut 的辅助注解,不使用可以不添加。 规定方法上使用的@HOSCacheable、@HOSCacheEvict、 @HOSCachePut中属性CacheNames的值。
若使用了该注解,方法上使用@HOSCacheable、@HOSCacheEvict、 @HOSCachePut注解中的属性CacheNames 可以不做单独声明,会默认使用此处的CacheNames。 但是,若类上@HOSCacheConfig中已经规定了CacheNames,方法上@HOSCacheable、@HOSCacheEvict、 @HOSCachePut 注解中单独声明了CacheNames,会以各自注解中的CacheNames值为准。
使用位置: 类
属性:
属性 | 功能描述 |
---|---|
cacheNames | 缓存名称,必须指定至少一个 |
使用例子: 结合@HOSCacheable注解使用,此时@HOSCacheable中属性CacheNames值为 @HOSCacheConfig中规定的cacheNames, 即cahceTest002
@HOSCacheConfig(cacheNames = "cahceTest002")
public class AccountService01 {
@HOSCacheable
public String getAccount(String testUserName, int value2) {
System.out.println("获取数据中。。1。。。。");
return testUserName + String.valueOf(new Random().nextInt(100));
}
}
# @HOSCacheable
功能描述:
根据注解属性 condition 以及属性 unless ,判断是否进行缓存。判断通过后, 根据 注解属性key中的规则 生成缓存key, 并到缓存中查找数据,若存在数据,不执行方法直接返回数据。 若不存在数据,在方法执行完成后将方法的出参作为缓存值保存到缓存库中
使用位置: 方法
属性:
属性 | 功能描述 |
---|---|
cacheNames | 缓存名称,若结合@HOSCacheConfig使用可以为空,否则,必须指定至少一个 |
key | 缓存的 key,可以为空。如果指定,要按照 SpEL 表达式编写,如果不指定,则按照方法的所有入参自动组合生成。例如:@HOSCacheable(value=”testcache”,key=”#id”) |
expireSecond | 缓存失效时间,单位为秒,默认为持久缓存 |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。例如:@HOSCacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | 否定缓存条件,使用 SpEL 编写,返回 true 或者 false。当条件结果为TRUE时,就不会缓存。@HOSCacheable(value=”testcache”,unless=”#userName.length()>2”) |
Spel的规则请参考下面的描述
SpEL简单使用:
要指定 属性key、condition、unless 的值时须使用SpEL表达式,使用 '#'+参数名称 指定到对应的入参
例如:
使用缓存注解的方法: public String getAccount(String testUserName, int value2)
入参的实际值: testUserName->"user01" , value2->1121
若使用 testUserName+"-"+value2 的格式生成key,则写作 #testUserName+'-'+#value2, 最后生成的结果为user01-1121。 使用在condition和unless中支持基础的判断语句,例如 #value2>1000 ,即判断 value2 的值是否大于1000, 最后得出boolean结果(true或者false)
复杂的使用请自行百度
@HOSCacheable(cacheNames = "cahceTest002" ,condition="#value2 > 100")
public String getAccount(String testUserName,int value2)
若只需要指定cacheNames,属性名称可以省略,例如
@HOSCacheable("cahceTest002")
public String getAccount(String testUserName,int value2)
key的默认生成规则:获取方法的所有入参,各个入参之间使用英文冒号(:)拼接。 例如:方法的所有入参为 "ceshi01",28,"山东" 三项,采用默认生成方式生成的key为 ceshi01:28:山东
# @HOSCachePut
功能描述:
根据注解属性 condition 以及属性 unless ,判断是否进行缓存。判断通过后, 根据 注解属性key中的规则 生成缓存key,在方法执行完成后,根据缓存key到缓存库中查找数据,若存在数据, 将方法的出参作为缓存值更新到对应的缓存key中。若不存在,将方法的出参作为缓存值保存到缓存库中
使用位置: 方法
属性:
属性 | 功能描述 |
---|---|
cacheNames | 缓存名称,若结合@HOSCacheConfig使用可以为空,否则,必须指定至少一个 |
key | 缓存的 key,可以为空。如果指定,要按照 SpEL 表达式编写,如果不指定,则按照方法的所有入参自动组合生成。例如:@HOSCacheable(value=”testcache”,key=”#id”) |
expireSecond | 缓存失效时间,单位为秒,默认为持久缓存 |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。例如:@HOSCacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | 否定缓存条件,使用 SpEL 编写,返回 true 或者 false。当条件结果为TRUE时,就不会缓存。@HOSCacheable(value=”testcache”,unless=”#userName.length()>2”) |
使用例子:指定CacheNames并执行key的生成方式
@HOSCachePut(cacheNames = "cahceTest001",key = "#testUserName")
public String getAccount004(String testUserName)
若只需要指定cacheNames,属性名称可以省略, 例如:
@HOSCachePut("cahceTest001")
public String getAccount004(String testUserName)
该处cacheNames属性值为"cahceTest001"
# @HOSCacheEvict
功能描述:
根据注解属性 condition 以及属性 unless ,判断是否进行缓存删除。判断通过后, 根据 注解属性key中的规则 生成缓存key,并到缓存库中查找数据, 若已存在,将缓存key以及对应的数据从缓存库中删除
使用位置: 方法
属性:
属性 | 功能描述 |
---|---|
cacheNames | 缓存名称,若结合@HOSCacheConfig使用可以为空,否则,必须指定至少一个 |
key | 缓存的 key,可以为空。如果指定,要按照 SpEL 表达式编写,如果不指定,则按照方法的所有入参自动组合生成。例如:@HOSCacheable(value=”testcache”,key=”#id”) |
condition | 缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存。例如:@HOSCacheable(value=”testcache”,condition=”#userName.length()>2”) |
unless | 否定缓存条件,使用 SpEL 编写,返回 true 或者 false。当条件结果为TRUE时,就不会缓存。@HOSCacheable(value=”testcache”,unless=”#userName.length()>2”) |
allEntries | 是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空缓存空间(cacheNames)的缓存数据 |
beforeInvocation | 是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存 |
使用例子: @HOSCacheEvict在方法上的使用,指定cacheNames并执行key的生成方式
@HOSCacheEvict(cacheNames = "cahceTest001",key = "#testUserName")
public String getAccount004(String testUserName)
若只需要指定cacheNames,属性名称可以省略, 例如:
@HOSCacheEvict("cahceTest001")
public String getAccount004(String testUserName)
该处cacheNames属性值为"cahceTest001"
# @HOSCaching
功能描述:
在一个方法上同一类型的注解只能存在一个,为支持同时多种缓存处理的情况,提供该注解。 提供cacheable、put、evict属性分别用于存放@HOSCacheable、@HOSCachePut、@HOSCacheEvict注解。
使用位置: 方法
属性:
属性 | 功能描述 |
---|---|
cacheable | 存放@HOSCacheable注解,可以为空 |
put | 存放@HOSCachePut注解,可以为空 |
evict | 存放@HOSCacheEvict注解,可以为空 |
使用例子: 在方法上的使用:
@HOSCaching(
cacheable = {
@HOSCacheable(value = "emp0")
},
put = {
@HOSCachePut(value = "emp1",key = "#testUserName"),
@HOSCachePut(value = "emp2",key = "#testUserName"),
},
evict = {
@HOSCacheEvict(value = "emp3",key = "#testUserName")
}
)
public String getAccount001(String testUserName)
注意:以上提到的五种注解均不可使用到Controller控制层
# 工具类提供的方法以及功能描述
本插件提供了两个工具类:CacheTenantUtil与CacheUtil。
CacheTenantUtil工具类支持多租户功能,根据多租户开关自动将租户id拼接到key中.
CacheUtil工具类中无其他特殊处理,缓存key由开发者自定义
工具类介绍如下:
# CacheTenantUtil
缓存工具类CacheTenantUtil,其提供的方法如下
/**
* 从缓存库中已存在的缓存数据
*
* cacheName 缓存名称,不可为空
* key 缓存键的参数,可传递多项,会根据默认key生成规则最终生成缓存key
*
*/
public static Object get(String cacheName, Object... key)
/**
* 向缓存库中存放数据
*
* cacheName 缓存名称,不可为空
* value 存入到缓存中的数据
* key 缓存键的参数,可传递多项,会根据默认key生成规则最终生成缓存key
*
*/
public static void put(String cacheName, Object value,Object... key);
/**
* 向缓存中存放数据,设置过期时间
*
* @param cacheName 缓存名称
* @param value 向缓存中存放的数据
* @param expireSecond 失效时间单位为秒
* @param key 缓存key参数
*/
public static void putESecond(String cacheName, Object value,int expireSecond,Object... key);
/**
* 删除缓存库中已存在的数据
*
* cacheName 缓存名称,不可为空
* key 缓存键的参数,可传递多项,会根据默认key生成规则最终生成缓存key
*
*/
public static void evict(String cacheName, Object... key)
/**
* 清除缓存库中对应cacheName(缓存名称)下所有的缓存数据
*
* @param cacheName 缓存名称,不可为空
*
*/
public static void clear(String cacheName)
/**
* 获取过期时间,单位为秒
*
* @param cacheName 缓存名称
* @param key 缓存键的参数,可传递多个,共同生成缓存key
* @return
*/
public static long getExpire(String cacheName, Object... key)
/**
* 根据 缓存名称 与 key 获取 缓存key列表
*
* @param cacheName 缓存名称
* @param key 缓存键的参数,可传递多个,共同生成缓存key
* @return @
*/
public static Set<String> getKeys(String cacheName,Object... key);
为与注解的互通使用,工具类提供的方法中均使用了 String cacheName 和 Object... key 作为入参。 工具类使用时,入参保持一致就行,不必关心缓存中具体使用的key的形式。 关于注解与该工具类的互通使用,可以参考注解与工具类互通使用示例
String cacheName为缓存名称,对应注解属性cacheNames。
Object... key 为缓存key参数。可传递多个共同生成最终的缓存key.
与注解的交互如下:
若使用注解时未指定注解的key属性(即采用默认的key生成方式), Object... key 传入的值为对应方法的入参; 例如:带有注解的方法入参为 test01(String value,String number) ,调用方式时传入的参数为 "test" 和 2233 ,则调用在使用工具类获取时, Object... key 中需要传入的参数为 "test",2233 两项
若指定了注解key属性,需传入与指定方式所对应的值;例如:带有注解的方法入参为 test01(String value,String number) , 调用方式时传入的参数为 "test" 和 2233 ,指定的key的spEl表达式为 #value+'_'+#number。 此时最终生成的缓存key为 test_2233。若想要通过工具类调用,Object... key 中需要传入 test_2233 一项。
其他场景下(无需与注解对应),只传入缓存key即可。
key的默认生成规则:获取方法的所有入参(对应方法中的 Object... key),各个入参之间使用英文冒号(:)拼接。 例如:方法的所有入参为 "ceshi01",28,"山东" 三项,采用默认生成方式生成的key为 ceshi01:28:山东
注意:若未开启租户功能或者未设置租户,生成的缓存key不拼接租户ID。
# CacheUtil
工具类CacheUtil提供的方法如下:
/**
* 获取缓存中的数据
*
* @param cacheName
* @param key
* @param <T>
* @return
*/
public static <T> T get(String cacheName, String key);
/**
* 向缓存中存放数据
*
* @param cacheName
* @param value
* @param key
*/
public static void put(String cacheName, Object value,String key);
/**
*删除缓存中的数据
*
* @param cacheName
* @param key
*/
public static void evict(String cacheName, String key);
/**
* 清理对应缓存名称下所有的缓存
*
* @param cacheName
*/
public static void clear(String cacheName);
/**
* 判断缓存key是否存在
*
* @param key 索引
* @return 是否
*/
public static boolean containKey(String cacheName,String key);
/**
* 获取过期时间,单位为秒.返回0代表永久有效,-1代表获取失败(key不存在)
*
* @param cacheName
* @param key
* @return
*/
public static int getExpire(String cacheName, String key);
/**
* 获取指定前缀的一系列key
*
* @param cacheName 缓存名称
* @param key 缓存key
* @return
*/
public static Set<String> getKeys(String cacheName,String key);
/**
* 向缓存中存放数据,设置过期时间
*
* @param cacheName 缓存名称
* @param value 向缓存中存放的数据
* @param expireSecond 失效时间单位为秒
* @param key 缓存key参数
*/
public static void putESecond(String cacheName,Object value,int expireSecond,String key);
# 使用示例
# 注解的使用
自定义类
/**
* 自定义的类
*/
@Service
public class AccountService {
/**
* HOSCacheable中的值为之前在配置项中配置过的CacheName的值,缓存的key值会在调用的时候自动生成
* 缓存端key是根据入参自动生成,其保存的数据为接口的返回值
* 调用方法时,根据该生成的key值到缓存中查找,如果找到直接返回缓存中的数据,若没有,将该key对应的数据放入缓存中
*
* 方法功能描述:1、打印数据 2、根据入参的testUserName和一个随机数生成返回值
*
* @param testUserName
* @param value2
* @return
*/
@HOSCacheable("cahceTest002")
public String getAccount(String testUserName, int value2) {
System.out.println("获取数据中。。1。。。。");
return testUserName + String.valueOf(new Random().nextInt(100));
}
}
方法调用
@Autowired
AccountService accountService;
public void testCache() throws Exception {
System.out.println("第一次执行。。。。。。");
String result1=accountService.getAccount("UserTestName228",1122);
System.out.println("结果1:"+result1);
System.out.println("第二次执行。。。。。。");
String result2=accountService.getAccount("UserTestName228",1122);
System.out.println("结果2:"+result2);
}
调用结果
如图中展示,第一次调用的时候进入到方法里面,并运算得到结果,第二次调用方式时,未进入方法内部,直接获取到缓存中的值
# 工具类的使用
CacheTenantUtil工具类使用示例和 CacheUtil工具类使用示例分别如下:
# CacheTenantUtil工具类使用示例
public void testCache() throws Exception {
String savedData="";
//初始化存放到缓存中的数据
List<String> arr=new ArrayList<>();
arr.add("11");
arr.add("33");
Map<String,List> map=new HashMap<>();
map.put("list",arr);
Object cache1=null;
//存储缓存数据
//第一个参数为cacheName(预先设置好的cacheName的值)
//第二个参数为需要存储的对象
//其他参数为key值,多个入参共同生成key
CacheTenantUtil.put("cahceTest002",map,"testName4",1);
//存储缓存数据,并设置过期时间
//第一个参数为cacheName(预先设置好的cacheName的值)
//第二个参数为过期时间
//第三个参数为需要存储的对象
//其他参数为key值,多个入参共同生成key
CacheTenantUtil.putESecond("cahceTest002",arr,600,"testName5");
//获取数据,第一个参数为cacheName(预先设置好的cacheName的值)
//其他参数为key值,多个入参共同生成key
cache1=CacheTenantUtil.get("cahceTest002","testName4",1);
System.out.println("结果1:"+cache1);
//删除key下的数据,第一个参数为cacheName(预先设置好的cacheName的值)
//其他参数为key值,多个入参共同生成key
CacheTenantUtil.evict("cahceTest002","testName4",1);
//查询该缓存名称对应的缓存下,所有的缓存key。缓存名称(cacheName)为cahceTest002
Set<String> keySet=CacheTenantUtil.getKeys("cahceTest002");
System.out.println("缓存名称cahceTest002中的key:");
keySet.stream().forEach(key ->{
System.out.println(key);
});
}
调用结果:
# CacheUtil工具类使用示例
String savedData="";
//初始化存放到缓存中的数据
List<String> arr=new ArrayList<>();
arr.add("11");
arr.add("33");
Map<String,List> map=new HashMap<>();
map.put("list",arr);
Object cache1=null;
//存储缓存数据,
//第一个参数为cacheName(预先设置好的cacheName的值)
//第二个参数为需要存储的对象
//第三个参数为缓存key
CacheUtil.put("cahceTest002",map,"customKey_1");
CacheUtil.put("cahceTest002",map,"customKey_3");
//存储缓存数据,并设置过期时间
//第一个参数为cacheName(预先设置好的cacheName的值)
//第二个参数为过期时间
//第三个参数为需要存储的对象
//第四个参数为缓存key
CacheUtil.putESecond("cahceTest002",arr,600,"customKey_2");
//获取数据
//第一个参数为cacheName(预先设置好的cacheName的值)
//第二个参数为缓存key
cache1=CacheUtil.get("cahceTest002","customKey_1");
System.out.println("结果1:"+cache1);
//删除key下的数据
//第一个参数为cacheName(预先设置好的cacheName的值)
//第二个参数为缓存key
CacheUtil.evict("cahceTest002","customKey_1");
//查询该缓存名称对应的缓存下,所有的缓存key。缓存名称(cacheName)为cahceTest002
Set<String> keySet=CacheUtil.getKeys("cahceTest002","");
System.out.println("缓存名称cahceTest002中的key:");
keySet.stream().forEach(key ->{
System.out.println(key);
});
调用结果:
# 注解与工具类互通使用示例
- 注解未指定key属性
使用注解存放缓存
@HOSCacheable("cacheTest001")
public String getAccount004(String testUserName)
使用该工具类获取缓存
CacheTenantUtil.get("cacheTest001",testUserName);
使用该工具类清理缓存
CacheTenantUtil.evict("cacheTest001",testUserName);
- 注解指定key属性
使用注解存放缓存
@HOSCacheable(cacheNames = "cacheTest001",key ="#testUserName+'-01'")
public String getAccount004(String testUserName)
此时,由于注解中key为使用者指定,因此在使用工具类操作缓存时,需要使用者自己完成拼接
若,testUserName值为 testUser,则根据示例中key属性中指定的方式,生成的key为 testUser-01,因此
使用该工具类获取缓存
CacheTenantUtil.get("cacheTest001","testUser-01");
使用该工具类清理缓存
CacheTenantUtil.evict("cacheTest001","testUser-01");