场景
SpringBoot中通过自定义缓存注解(AOP切面拦截)实现数据库数据缓存到Redis:
SpringBoot中通过自定义缓存注解(AOP切面拦截)实现数据库数据缓存到Redis_霸道流氓气质的博客-CSDN博客
上面讲的通过自定义注解的方式实现查询数据库数据缓存,除此之外还有更好的轮子。
JetCache
JetCache是由阿里巴巴开源的通用缓存访问框架,如果你对Spring Cache很熟悉的话,请一定花一点时间了解一下JetCache,
它更好用。JetCache提供的核心能力包括:
提供统一的,类似jsr-107风格的API访问Cache,并可通过注解创建并配置Cache实例
通过注解实现声明式的方法缓存,支持TTL和两级缓存
分布式缓存自动刷新,分布式锁 (2.2+)
支持异步Cache API
Spring Boot支持
Key的生成策略和Value的序列化策略是可以定制的
针对所有Cache实例和方法缓存的自动统计
官方仓库地址:
https://github.com/alibaba/jetcache
中文文档地址:
https://github.com/alibaba/jetcache/blob/master/docs/CN/GettingStarted.md
注:
博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
实现
1、首先搭建SpringBoot项目并引入相关web、mysql、mybatis等相关依赖,然后添加JetCache依赖
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.6.0</version>
</dependency>
注意这里的版本为2.6.0,要注意从2.7.0开始有些改动,具体可查看官方文档说明。
这里附其他所需的依赖,其他依赖以及版本具体根据自己需要决定。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--MySQL驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--MyBatis整合SpringBoot框架的起步依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.6.0</version>
</dependency>
</dependencies>
2、找到yml配置文件,添加如下配置
jetcache:
#统计间隔,0表示不统计
statIntervalMinutes: 15
areaInCacheName: false
local:
default:
type: linkedhashmap
keyConvertor: fastjson
remote:
default:
type: redis
keyConvertor: fastjson
valueEncoder: java
valueDecoder: java
poolConfig:
minIdle: 5
maxIdle: 20
maxTotal: 50
host: 127.0.0.1
port: 6379
password: 123!
注意这里的最后面添加了jedis连接redis时的密码,这里本地的redis是需要密码验证的。
其他具体配置参考官方文档:
https://github.com/alibaba/jetcache/blob/master/docs/CN/Config.md
配置通用说明如下
属性 | 默认值 | 说明 |
---|---|---|
jetcache.statIntervalMinutes | 0 | 统计间隔,0表示不统计 |
jetcache.areaInCacheName | true(2.6-) false(2.7+) | jetcache-anno把cacheName作为远程缓存key前缀,2.4.3以前的版本总是把areaName加在cacheName中,因此areaName也出现在key前缀中。2.4.4以后可以配置,为了保持远程key兼容默认值为true,但是新项目的话false更合理些,2.7默认值已改为false。 |
jetcache.hiddenPackages | 无 | @Cached和@CreateCache自动生成name的时候,为了不让name太长,hiddenPackages指定的包名前缀被截掉 |
jetcache.[local/remote].${area}.type | 无 | 缓存类型。tair、redis为当前支持的远程缓存;linkedhashmap、caffeine为当前支持的本地缓存类型 |
jetcache.[local/remote].${area}.keyConvertor | fastjson2 | key转换器的全局配置,2.6.5+已经支持的keyConvertor:fastjson2 /jackson ;2.6.5-只有一个已经实现的keyConvertor: fastjson 。仅当使用@CreateCache且缓存类型为LOCAL时可以指定为none ,此时通过equals方法来识别key。方法缓存必须指定keyConvertor |
jetcache.[local/remote].${area}.valueEncoder | java | 序列化器的全局配置。仅remote类型的缓存需要指定,2.7+可选java /kryo /kryo5 ;2.6-可选java /kryo |
jetcache.[local/remote].${area}.valueDecoder | java | 序列化器的全局配置。仅remote类型的缓存需要指定,2.7+可选java /kryo /kryo5 ;2.6-可选java /kryo |
jetcache.[local/remote].${area}.limit | 100 | 每个缓存实例的最大元素的全局配置,仅local类型的缓存需要指定。注意是每个缓存实例的限制,而不是全部,比如这里指定100,然后用@CreateCache创建了两个缓存实例(并且注解上没有设置localLimit属性),那么每个缓存实例的限制都是100 |
jetcache.[local/remote].${area}.expireAfterWriteInMillis | 无穷大 | 以毫秒为单位指定超时时间的全局配置(以前为defaultExpireInMillis) |
jetcache.remote.${area}.broadcastChannel | 无 | jetcahe2.7的两级缓存支持更新以后失效其他JVM中的local cache,但多个服务共用redis同一个channel可能会造成广播风暴,需要在这里指定channel,你可以决定多个不同的服务是否共用同一个channel。如果没有指定则不开启。 |
jetcache.local.${area}.expireAfterAccessInMillis | 0 | 需要jetcache2.2以上,以毫秒为单位,指定多长时间没有访问,就让缓存失效,当前只有本地缓存支持。0表示不使用这个功能。 |
3、找到启动类添加如下两个注解来开启注解支持
@SpringBootApplication
@EnableMethodCache(basePackages = "com.badao.demo")
添加位置
4、使用注解@CreateCache创建缓存实例
首先声明一个User,这里使用了lombok注解
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
private static final long serialVersionUID = -5514139686858156155L;
private Integer id;
private Integer userId;
private String name;
private Integer age;
}
然后在serviceImpl中声明实例
@CreateCache(expire = 100)
private Cache<Long, User> userCache;
然后再service具体方法中使用,使用方式与map一样
@Override
public void cacheHandler() {
//创建缓存并使用,使用方式和map一样
User user = new User();
user.setName("badao");
userCache.put(1l,user);
User user1 = userCache.get(1l);
System.out.println(user1);
//userCache.remove(1l);
}
注意这里的注解只声明了过期时间,其他都是使用默认属性,这里表示100秒过期。
默认存储类型为远端即redis存储。
cacheType有LOCAL/REMOTE/BOTH三种选择,分别代表本地内存/远程Cache Server(例如Redis)/两级缓存,
可根据情况选用,合理的使用LOCAL或BOTH类型可以降低Cache Server的压力以及我们提供的服务的响应时间。
我们在controller中调用该service并进行测试
发现其缓存成功,因为没指定key所以是默认名字。
比如我们修改上面的注解的内容为
@CreateCache(name = "userCache",expire = 100,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.LOCAL)
这里就设置了将其缓存在内存并指定了名字。
还可以如此设置
@CreateCache(name = "userCache",expire = 100,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.BOTH,localLimit = 50)
更多详细配置参考官方文档:
https://github.com/alibaba/jetcache/blob/master/docs/CN/CreateCache.md
@CreateCache属性表
属性 | 默认值 | 说明 |
---|---|---|
area | “default” | 如果需要连接多个缓存系统,可在配置多个cache area,这个属性指定要使用的那个area的name |
name | 未定义 | 指定缓存的名称,不是必须的,如果没有指定,会使用类名+方法名。name会被用于远程缓存的key前缀。另外在统计中,一个简短有意义的名字会提高可读性。如果两个@CreateCache 的name 和area 相同,它们会指向同一个Cache 实例 |
expire | 未定义 | 该Cache实例的默认超时时间定义,注解上没有定义的时候会使用全局配置,如果此时全局配置也没有定义,则取无穷大 |
timeUnit | TimeUnit.SECONDS | 指定expire的单位 |
cacheType | CacheType.REMOTE | 缓存的类型,包括CacheType.REMOTE、CacheType.LOCAL、CacheType.BOTH。如果定义为BOTH,会使用LOCAL和REMOTE组合成两级缓存 |
localLimit | 未定义 | 如果cacheType为CacheType.LOCAL或CacheType.BOTH,这个参数指定本地缓存的最大元素数量,以控制内存占用。注解上没有定义的时候会使用全局配置,如果此时全局配置也没有定义,则取100 |
serialPolicy | 未定义 | 如果cacheType为CacheType.REMOTE或CacheType.BOTH,指定远程缓存的序列化方式。JetCache内置的可选值为SerialPolicy.JAVA和SerialPolicy.KRYO。注解上没有定义的时候会使用全局配置,如果此时全局配置也没有定义,则取SerialPolicy.JAVA |
keyConvertor | 未定义 | 指定KEY的转换方式,用于将复杂的KEY类型转换为缓存实现可以接受的类型,JetCache内置的可选值为KeyConvertor.FASTJSON和KeyConvertor.NONE。NONE表示不转换,FASTJSON通过fastjson将复杂对象KEY转换成String。如果注解上没有定义,则使用全局配置。 |
5、使用注解@Cached创建方法缓存
使用@Cached方法可以为一个方法添加上缓存。JetCache通过Spring AOP生成代理,来支持缓存功能。
注解可以加在接口方法上也可以加在类方法上,但需要保证是个Spring bean。
比如我们service中将一个查询mysql数据库的方法添加注解并指定名字和过期时间
@Cached(name = "methodCacheHandler",expire = 3600)
List<User> methodCacheHandler();
方法具体实现
@Override
public List<User> methodCacheHandler() {
return userMapper.findAll();
}
调用该方法会发现只有第一次查询了数据库
6、使用注解@CacheRefresh实现自动刷新
如果需要定期从数据库中查询并更新一次缓存数据可以这样用
@Cached(name = "methodCacheHandler",expire = 3600)
@CacheRefresh(timeUnit = TimeUnit.SECONDS,refresh = 10)
List<User> methodCacheHandler();
比如这里设置10秒自动刷新一次,测试效果
更多功能和说明参考官方文档。
7、遇到的那些坑
如果提示:
The dependencies of some of the beans in the application context from a cycle:
redisAutoInit->springConfigProvider
在yml中spring节点下配置允许循环依赖
#解决jetcache循环依赖问题
main:
allow-circular-references: true
如果提示:
jetcache(RedisCache) PUT error,...Could not get a resource from the pool
则检查配置的redis是否启动以及连接信息是否正确。
如果提示:
JedisDataException:NoAuth Authentication required
则在配置文件中加入redis的连接密码