一个应用主要瓶颈在于数据库的IO,大家都知道内存的速度是远远快于硬盘的速度(即使固态硬盘与内存也无法比拟)。
应用之中经常会遇到某些数据变化的可能性很小。假如我们使用传统的方式每次都通过接口与数据库打交道去请求获得,每次既消耗了内存资源、网络资源、数据库资源、CPU资源,又导致大量的时间耗费在数据库查询,及远程方法调用上,从而导致程序性能的恶化。
这种场景就是需要使用缓存来解决这类问题。我们把数据缓存在内存之中,以后每次获取直接内存之中获得;使得程序获得极大的性能提升。
SpringCache相当于一个抽象接口,在其底层可以切换各种Cache的实现,当缓存数据时,只需要注入SpringCache对应的注解,即可实现缓存的功能,大大的提高了缓存的效率,这就是Spring自带缓存SpringCache的使用原理
Springcache默认的缓存实现是simple(内存级),当然可以更换成其他实现,常见的有如下
EhCache:此缓存框架一直伴随着Spring,Hibernate,Mybatis等等。在SpringBoot出来之前都已经广泛的使用来做为一级缓存
Guava: Google出品的框架,也支持缓存
Redis:在我们日常开发之中经常使用的;并且被大众广泛接受的速度极快的缓存
memcached:是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。
Spring缓存的接口:
org.springframework.cache.Cache ;
org.springframework.cache.CacheManager
这两个接口都在context中,一个是用来提供缓存,一个是用来提供管理缓存。
CacheManager是Spring提供的各种缓存技术抽象接口,
Cache接口包含缓存的各种操作(增加、删除、获得缓存,我们一般不会直接和此接口打交道)。
Spring支持的CacheManager实现如下图:

使用缓存需要引入的依赖是
-
-
org.springframework.boot -
spring-boot-starter-cache -
EnableCaching
标注于SpringBoot应用启动类上,添加此注解表示开启Spring Cache缓存;移除表示关闭缓存。如果在全局配置文件中添加如下配置,即使在启动类上标注EnableCaching注解,Spring Cache缓存然后是关闭状态。
- spring:
- cache:
- type: none
-
如果应用中自定义独立于Spring容器的缓存,则不受此配置影响。
CacheConfig
标注于类上,更具体的说是标注于业务服务类上。统一配置如下参数信息:
| 参数 | 含义 | 使用说明 |
|---|---|---|
cacheManager | 缓存管理器 | 缺省指首要的CacheManager |
cacheNames | 缓存名 | |
keyGenerator | key值生成器 |
在类上统一进行配置,类下的方法自动继承相应的配置。
Cacheable
添加缓存的核心注解,分两种情况:一是对应key值未有缓存数据,先执行方法,然后根据condition和unless条件决定是否添加缓存;二是对应key值已有缓存,不执行方法体,直接返回数据。
- /**
- *value:自定义缓存空间名
- *key:缓存的key
- */
- @Cacheable(value = "cacheSpace",key ="#id" )
- public List list(String id){
- return Arrays.asList("1","2","3");
- }
基础参数
| 参数 | 含义 | 使用说明 |
|---|---|---|
cacheManager | 缓存管理器 | 缺省指首要的CacheManager |
cacheNames | 缓存名 | |
keyGenerator | key值生成器 | |
key | key值 |
参数keyGenerator与key是互斥的,当key存在时keyGenerator配置自动失效。
高级参数
| 参数 | 含义 | 默认值 | 使用说明 |
|---|---|---|---|
condition | 缓存条件 | 指示满足条件方执行缓存操作,一般使用参数作为条件 | |
unless | 否定缓存 | 当条件为 true ,方法的返回值不会被缓存 | |
sync | 同步状态 | false | 表示将方法执行结果以何种方式存入缓存 |
CachePut
更新缓存注解。不管对应key值是否有缓存数据,都执行。
基础参数
| 参数 | 含义 | 使用说明 |
|---|---|---|
cacheManager | 缓存管理器 | 缺省指首要的CacheManager |
cacheNames | 缓存名 | |
keyGenerator | key值生成器 | |
key | key值 |
高级参数
| 参数 | 含义 | 使用说明 |
|---|---|---|
condition | 缓存条件 | 指示满足条件方执行缓存操作,一般使用参数作为条件 |
unless | 否定缓存 | 当条件为 true ,方法的返回值不会被缓存 |
CacheEvict
主动清除缓存注解。
基础参数
| 参数 | 含义 | 使用说明 |
|---|---|---|
cacheManager | 缓存管理器 | 缺省指首要的CacheManager |
cacheNames | 缓存名 | |
keyGenerator | key值生成器 | |
key | key值 |
高级参数
| 参数 | 含义 | 默认值 | 使用说明 |
|---|---|---|---|
condition | 缓存条件 | 指示满足条件方执行缓存操作,一般使用参数作为条件 | |
allEntries | 所有缓存 | false | 表示是否清空当前CacheName对应的所有缓存 |
beforeInvocation | 调用前 | false | 表示是否在方法调用前清空缓存 |
默认cache接口的实现simple(内存级),直接使用上面的注解即可,没有什么需要配置的,可以自己选择合适的缓存,
可以在spring-boot-dependencies发现有Echcache依赖,所以我们只需引入依赖,不需要版本
需要导入的依赖
- <dependency>
- <groupId>net.sf.ehcache</groupId>
- <artifactId>ehcache</artifactId>
- </dependency>
配置
- spring:
- cache:
- type: EHCACHE
还需要一个Ehcache的配置文件ehcache.xml
- "1.0" encoding="UTF-8"?>
- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
- updateCheck="false">
-
- <diskStore path="java.io.tmpdir/Tmp_EhCache"/>
-
-
- <defaultCache
- eternal="false"
- maxElementsInMemory="10000"
- overflowToDisk="false"
- diskPersistent="false"
- timeToIdleSeconds="1800"
- timeToLiveSeconds="259200"
- memoryStoreEvictionPolicy="LRU"/>
-
- <cache
- name="cloud_user"
- eternal="false"
- maxElementsInMemory="5000"
- overflowToDisk="false"
- diskPersistent="false"
- timeToIdleSeconds="1800"
- timeToLiveSeconds="1800"
- memoryStoreEvictionPolicy="LRU"/>
-
- ehcache>
使用方式还是用上面的注解
引入依赖
-
-
org.springframework.boot -
spring-boot-starter-cache -
-
-
-
org.springframework.boot -
spring-boot-starter-data-redis -
注意:这里是把redis作为cache实现进行整合,即springcache整合redis,并不是springboot整合redis
配置
- spring:
- cache:
- type: EHCACHE
- redis:
- #是否缓存空值
- cache-null-values: true
- #是否使用前缀
- use-key-prefix: true
- #前缀
- key-prefix: test
- #缓存时间
- time-to-live: 10s
- redis:
- host: localhost
- port: 6379
使用方式还是用上面的注解
下载安装memcached
地址Windows 下安装 Memcached | 菜鸟教程
下载后解压,cmd执行exe文件
memcached.exe -d install
安装如果出现failed to install servise or service is already installed,此时使用管理员身份打开cmd执行上面安装命令即可
然后启动和停止服务
memcached.exe -d start
memcached.exe -d stop
boot对memcached没有提供相应的整合,需要使用编码方式实现客户端管理,memcached客户端有一下三个
memcached client for java:最早期客户端 稳定可靠 用户群广(类似redis中的jedis)
SpyMemcached :效率更高
Xmemcached:并发处理更好
这里演示三个最好的Xmemcached使用
- <dependency>
- <groupId>com.googlecode.xmemcached</groupId>
- <artifactId>xmemcached</artifactId>
- <version>2.4.7</version>
- </dependency>
配置bean
- @Configuration
- public class XMemcachedConfig {
- @Bean
- public MemcachedClient memcachedClient() throws IOException {
- XMemcachedClientBuilder xMemcachedClientBuilder = new XMemcachedClientBuilder("localhost:11211");
- //自己根据需要设置其他参数
- xMemcachedClientBuilder.setConnectionPoolSize(20);
- MemcachedClient memcachedClient = xMemcachedClientBuilder.build();
- return memcachedClient;
- }
- }
测试
- @RequestMapping("mSet")
- @ResponseBody
- public String mSet() throws InterruptedException, TimeoutException, MemcachedException {
- memcachedClient.set("token",0,Arrays.asList("1","2","3"));
- return "ok";
- }
- @RequestMapping("mGet")
- @ResponseBody
- public String mGet() throws InterruptedException, TimeoutException, MemcachedException {
- return memcachedClient.get("token").toString();
- }
详情教程
上面几种缓存技术有以下几点特点
1、配置方式多样性,有xml中配置的、有yml配置文件的、有代码中写的,比较散乱
2、缓存有本地方案和远程方案(redis)
阿里提供的jetcache设定了本地缓存和远程缓存的多级缓存解决方案,用来替代spring-cache的
LinkedHashMap
Caffeine
Redis(本文选择远程方案)
Tair
使用jetcache之后就需要引入spring-boot-starter-cache,加入jetcache依赖
-
com.alicp.jetcache -
jetcache-starter-redis -
2.6.2 -
注意:boot整合jetcache只需引入上面依赖即可,如果不是boot整合,需要引入的是
jetcache anno和jetcache core两个依赖
jetcache远程&本地缓存方案
配置
- jetcache:
- #area是否进入拼接到缓存的key
- areaInCacheName: false
- #远程配置 默认default即可,远程方案使用redis ,其中poolConfig必须配置
- remote:
- default:
- type: redis
- host: localhost
- port: 6379
- keyConvertor: fastjson
- valueEncode: java
- valueDecode: java
- poolConfig:
- maxTotal: 50
- minIdle: 5
- maxIdle: 20
- test:
- type: redis
- host: localhost
- port: 6379
- keyConvertor: fastjson
- valueEncode: java
- valueDecode: java
- poolConfig:
- maxTotal: 50
- minIdle: 5
- maxIdle: 20
- #本地缓存配置
- local:
- default:
- type: linkedhashmap
- keyConvertor: fastjson
- valueEncode: java
- valueDecode: java
启动类开启缓存
- @SpringBootApplication
- //jetache缓存开启
- @EnableCreateCacheAnnotation
- public class TestApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(TestApplication.class, args);
- }
- }
- /**
- *定义缓存对象
- * area:和配置文件配置的要对应,如果配置文件remote只有default 这个area可以省略
- * name:空间配置 最好使用下划线或者其他符号和缓存的key隔开
- * expire:过期时间 默认单位秒
- * timuit:可选配置,默认单位秒
- * cacheType:当前缓存类型,只在本地缓存还是远程,
- * 取值CacheType.BOTH,CacheType.REMOTE CacheType.LOCAL三个取值 默认REMOTE
- */
- @CreateCache(area = "test",name = "testCache_",expire = 3600,timeUnit = TimeUnit.SECONDS,cacheType = CacheType.REMOTE)
- private Cache
jetCache; -
- public void jetCachePut(){
- //redis中的key是:test_testCache_token
- jetCache.put("token","111111111111111111");
- }
- public String jetCacheGet(){
- return jetCache.get("token");
- }
jetcache方法缓存
需要在启动类开启方法缓存注解
- @SpringBootApplication
- //jetache缓存开启
- @EnableCreateCacheAnnotation
- //开启方法缓存
- @EnableMethodCache(basePackages = {"com.test"})
- public class TestApplication {
-
- public static void main(String[] args) {
- SpringApplication.run(TestApplication.class, args);
- }
- }
使用如下
- /**
- * 方法缓存注解(使用方法缓存时放入缓存的实体类要实现序列化接口)
- */
- @Cached(name = "user_",key="#id",expire = 3600,cacheType = CacheType.BOTH)
- public User getById(Integer id){
- return userDao.getById(id);
- }
-
- /**
- * 更新数据时同时把缓存中的数据更新
- * vaule表示新的数据
- */
- @CacheUpdate(name = "user_",key="#user.id",value = "#user")
- public void updateUser(User user){
- userDao.update(user);
- }
- /**
- * 删除数据时候同时删除缓存中的数据
- * vaule表示新的数据
- */
- @CacheInvalidate(name = "user_",key = "#id")
- public void delUser(Integer id){
- userDao.delUser(id);
- }
如果同一套系统部署到两台机器,a机器改了数据但是b没有收到通知,此时可以使用cache提供的一个定义刷新缓存的注解
- @Cached(name = "user_",key="#id",expire = 3600,cacheType = CacheType.BOTH)
- @CacheRefresh(refresh = 5)
- public User getById(Integer id){
- return userDao.getById(id);
- }
查看jetcache缓存报告报表
只需增加一个配置
- jetcache:
- #查看缓存报告:1min后
- statIntervalMinutes: 1
控制台定时打印缓存命中相关

j2cache是一个缓存整合框架,使各种缓存配合使用,自身不提供缓存
使用参考视频