-
Notifications
You must be signed in to change notification settings - Fork 23
redisCli annotation 文档
<dependency>
<groupId>com.vdian.redis</groupId>
<artifactId>redisCli-annotation</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
- 配置:
在Spring配置文件中加入如下两个配置:
<!-- 开启AOP自动代理 -->
<aop:aspectj-autoproxy/>
<!-- 加载com.vdian.redis.annotation.core.CacheManageAspect -->
<context:component-scan base-package="com.vdian.redis.annotation.core"/>
- 加入缓存
在打算使用缓存的方法前添加@Cached
注解, 并在想要组装成Key的参数前添加@CacheKey
注解:
@Cached(namespace = "feedcenter", expireTime = CacheExpireTime.ONE_HOUR)
public AuthorFeed getAuthorFeed(@CacheKey(prefix = "feedId:") Long feedId) {
// ...
}
添加如上注解后
CacheManageAspect
就会拼装出feedId:[feedId-Value]
作为Key去查询Redis, 如果没有命中则回头执行getAuthorFeed()
方法, 得到返回值AuthorFeed
之后写入缓存, 并返回.
- 失效缓存
在需要失效缓存的方法前添加@CacheInvalid
注解, 并在想要组装成Key的参数前添加@CacheKey
注解:
@CacheInvalid(namespace = "feedcenter")
public int deleteFeed(@CacheKey(prefix = "feedId:") long feedId, String authorId) {
// ...
}
添加如上注解后
CacheManageAspect
就会拼装出feedId:[feedId-Value]
作为Key去删除Redis中的缓存(虽然deleteFeed()
方法还有一个authorId
参数, 但他并未被@CacheKey
标注,因此他并不会成为Key的一部分
redisCli-annotation包一共提供三个注解
@Cached
、@CacheInvalid
、@CacheKey
.
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cached {
/**
* @return cache命名空间
*/
String namespace();
/**
* @return cache过期时间. Unit: second
*/
int expireTime() default CacheExpireTime.FOREVER;
/**
* @return 多部分key之间的分隔符(如 part1:part2:part3)
*/
String keySeparator() default ":";
}
属性 | 描述 |
---|---|
namespace |
namespace (必填) |
expireTime |
缓存过期时间, 单位为秒. 在CacheExpireTime 接口中定义了一些推荐值, 也可自定义 (选填, 默认永不过期) |
keySeparator |
如果一个Key由多部分构成, 可由keySeparator 对其进行连接, 详见keySeparator 示例 (选填: 默认为":" ) |
-
keySeparator
示例
@Cached(namespace = "feedcenter", keySeparator="-")
int deleteFeed(@CacheKey(prefix = "feedId:") long feedId, @CacheKey(prefix = "authorId:")String authorId) {
// ...
}
则最后拼装起来的key为
feedId:[feedId-Value]-authorId:[authorId-Value]
, Key的两个部分以-
连接.
@Target(value = ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheInvalid {
/**
* @return cache命名空间
*/
String namespace();
/**
* @return 多部分key之间的分隔符(如 part1:part2:part3)
*/
String keySeparator() default ":";
}
namespace
与keySeparator
含义与@Cached
相同.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface CacheKey {
/**
* @return key前缀(如 参数值为123, 前缀prefix为id, 则本部分key拼装起来就可以是: id123)
*/
String prefix() default "";
/**
* @return 是否是一个批量key, 当要组装的Key参数为Collection(及其子类), 返回值为Collection/Map(及其子类)时需要用到
*/
boolean batchKey() default false;
/**
* @return 当batchKey为true, 且返回值为Collection(及其子类)时使用, 以说明Result对象的哪一个属性与key对应
*/
String resultExpression() default "";
/**
* @return 当想要使用一个对象的某个属性(如User的id属性)作为key时使用(如: keyExpression="id")
*/
String keyExpression() default "";
}
@CacheKey
是redisCli-annotation
包的核心, 封装了缓存Key的拼装/解析规则, @Cached
以及@CacheInvalid
注解均需配合@CacheKey
才能生效.
属性 | 描述 |
---|---|
prefix |
指定Key拼装前缀, 详见prefix 示例 |
batchKey |
标明该Key是否为一个批量Key, 详见batchKey 示例 |
resultExpression |
当batchKey 为true 且方法返回Collection (及其子类)时使用, 详见batchKey 与resultExpression 示例 |
keyExpression |
如果方法形参为Object , 但并不希望将整个Object 作为Key时使用, 详见keyExpression 示例 |
-
prefix
示例:
@Cached(namespace = "feedcenter")
int deleteFeed(@CacheKey(prefix = "feedId:") long feedId, String authorId) {
// ...
}
由于指定了
prefix
, 则最后拼装Key为feedId:[feedId-Value]
, 否则裸Key应该为[feedId-Value]
. 使用prefix
可防止当namespace
相同时的Key冲突.
-
batchKey
与resultExpression
示例:
@Cached(namespace = "feedcenter")
public List<FeedUser> getFeedUsers(@CacheKey(prefix = "userId:", batchKey = true, resultExpression = "id") List<Long> feedIds) {
// ...
}
batchKey
标定该Key为一个批量Key, 比如以(1,2,3,4,5)List
为参数调用getFeedUsers()
方法, CacheManageAspect
就会拼装出:
userId:1
userId:2
userId:3
userId:4
userId:5
等一批Key去查询缓存, 如果其中只有userId:1
、userId:2
、userId:4
命中缓存, CacheManageAspect
则会继续以(3, 5)List
去继续调用getFeedUsers()
方法, 得到返回结果写入缓存. 最后将缓存查询结果与方法执行结果合并返回.
由于@CacheKey
中标注了resultExpression = "id"
, 因此我们可以将返回值FeedUser
中的id
属性与Key中的Id值对一一对应起来. 比如以(1,2,3,4,5)
参数传入, 我们也只会返回id为(1,2,3,4,5)
的FeedUser对象组成的List.
-
batchKey
与无resultExpression
示例:
@Cached(namespace = "feedcenter")
public Map<Long, FeedUser> getFeedUsers(@CacheKey(batchKey = true) List<Long> feedIds) {
// ...
}
虽然@CacheKey
中指定了batchKey
, 但并未指定resultExpression
, 这是因为方法的返回值为Map
, 我们默认Map的key直接对应参数值
:
Map<Long, FeedUser> = {
id=1 -> id=1的FeedUser对象;
id=2 -> id=2的FeedUser对象;
...
}
-
keyExpression
示例:
@CacheInvalid(namespace = "feedcenter")
public boolean unLike(@CacheKey(keyExpression = "feedId") FeedLike feedLike) {
// ...
}
虽然@CacheKey
标记的是一个FeedLike
对象, 但有时我们并不想将整个对象作为Key, 我们希望用他的一个属性如feedId
作为Key, 因此就可以指定keyExpression = "feedId"
.
@Cached(namespace = "feedcenter")
public List<FeedUser> getFeedUsers(@CacheKey(prefix = "userId:", batchKey = true, resultExpression = "id") List<Long> feedIds) {
// ...
}
比如以(1,2,3)List
调用getFeedUsers()
方法, 却希望返回{FeedUser(id=1), FeedUser(id=2), FeedUser(id=3), FeedUser(id=4)}List
的对象列表, 多了一个id为4的FeedUser对象, 这种情况我们无法做到.
@Cached(namespace = "feedcenter")/@CacheInvalid(namespace = "feedcenter")
public List<FeedUser> getFeedUsers(List<Long> feedIds) {
// ...
}
这样使用会直接抛出异常, Redis缓存不能没有Key.
@Cached(namespace = "feedcenter")
public ReturnType getFeedUsers(@CacheKey(batchKey = true) List<Long> feedIds, @CacheKey(batchKey = true) List<Long> authorIds ) {
// ...
}
如果Key是多部分Key(有多个@CacheKey
注解), 且有多个批量属性(包含多个batchKey = true
属性), 则在第一次运行时就会抛出异常.
@Cached(namespace = "feedcenter")
public ReturnType getFeedUsers(@CacheKey(batchKey = true) Map<Long, FeedUser> map) {
// ...
}
这种希望以Map的KeySet拼装Key列表的用法还不支持, 我们争取在下一期加入.
- by 攻城师@翡青