Spring官方提供了Spring Cache在Spring Boot中的starter,所以要启动spring cache非常简便。
一、导入缓存需要用到的依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--这里我们使用基于redis的cache,所以引入redis的starter-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
二、使用@EnableCaching注解启用cache
@SpringBootApplication
@EnableCaching
@MapperScan("com.dongrui.study.spring_cache.mapper")
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
三、各类注解的使用及简单解析
@Cacheable注解
@Cacheable(value = "test", key = "'user:'+#conditions[id]+':info'",sync=true)
@Select("select * from tb_test_user t where t.id = #{id}")
Map<String, Object> getTestUser(Map<String, Object> conditions);
解析:
-
Cacheable注解可以标注在方法上,也可以标注在类上,当标注在方法上,是用来表明这个方法的返回值需要缓存,当标注在类上,则表明该类的所有方法都支持缓存;
-
value属性表示该缓存使用的命名域,其具体的作用方式是在缓存的key值前面拼接上_[namespace]::_,也可以使用cacheName属性,作用相同,value或cacheName是一个String[],意味着我们可以指定多个命名域,这时每个命名域都会缓存一份数据,在获取时只要任一命名域中查找到匹配的数据,就会从缓存中获取并返回;
-
key属性是用于设置该缓存的key值命名,上面的配置意为:‘user:‘字符串拼接上conditions中key为’id’所对应的value,然后在拼接上’:info’。如果不设置key,Spring Cache会根据参数自动生成一个key值,为了便于管理,还是尽量设置key值;
示例:test::user:1:info
-
sync属性是一个boolean值,默认为false,该属性为true时表明该key对应的缓存在被访问时需要同步进行,为false时允许异步访问;
-
使用jmeter进行压力测试,使用缓存与不使用缓存分别循环请求2000次,使用缓存比不使用缓存响应速度提升50%以上,该测试并不十分严谨,仅供参考;
@CacheEvict注解
@CacheEvict(value="test", key="'user:'+#params[id]+':info'")
@Update("update tb_test_user set name = #{newName} where id = #{id}")
int modifyTestCacheUser(Map<String, Object> params);
解析:
- CacheEvict顾名思义,是用来清除指定的缓存的;
- value和key属性的功能与使用方法与Cacheable一致,表示要清除指定命名域下指定key值的缓存;
- allEntries属性,boolean类型,表示是否要清除指定域名下所有的缓存,默认为false,当该属性为true时,key属性失效;
- 上述代码意为在更新某个数据后,将该数据的缓存清除掉,从而达到更新缓存的目的;
@CachePut注解
@CachePut(value = "test", key = "'user:'+#conditions[id]+':info'")
@Select("select * from tb_test_user t where t.id = #{id}")
Map<String, Object> getTestUser2(Map<String, Object> conditions);
解析:
- CachePut的使用方法与@Cacheable完全一致;
- CachePut因为没有涉及到缓存的访问,所以没有sync属性;
- 区别:使用@Cacheable时,Spring Cache会先判断缓存中是否有已经存在的缓存,如果没有则执行方法并写入缓存然后返回,如果有则直接从缓存中获取然后返回;而当使用@CachePut时,始终会执行方法并写入缓存然后返回,相当于此注解只影响写入缓存,而不对方法的执行以及返回值产生影响;
四、缓存类型配置
自动配置支持的缓存类型
从CacheType中可以看到Spring Cache自动配置支持的缓存类型,精简后的源码如下:
package org.springframework.boot.autoconfigure.cache;
public enum CacheType {
GENERIC,
JCACHE,
EHCACHE,
HAZELCAST,
INFINISPAN,
COUCHBASE,
REDIS,
CAFFEINE,
SIMPLE,
NONE
}
通过org.springframework.boot.autoconfigure.cache.CacheProperties我们可以知道,我们可以设置spring.cache.type属性来设置我们要使用的缓存,示例如下:
spring:
cache:
type: redis
自定义cacheManager
如果上述缓存类型不能满足,那么还可以自定义cacheManager来使用我们希望使用的缓存,这里可以参考org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration中对cacheManager的实现,代码如下:
@Bean
public RedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory,
ResourceLoader resourceLoader) {
RedisCacheManagerBuilder builder = RedisCacheManager
.builder(redisConnectionFactory)
.cacheDefaults(determineConfiguration(resourceLoader.getClassLoader()));
List<String> cacheNames = this.cacheProperties.getCacheNames();
if (!cacheNames.isEmpty()) {
builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
}
return this.customizerInvoker.customize(builder.build());
}
以及org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration中对cacheManager的实现,代码如下:
@Bean
public EhCacheCacheManager cacheManager(CacheManager ehCacheCacheManager) {
return this.customizers.customize(new EhCacheCacheManager(ehCacheCacheManager));
}
说明:这里仅做一个思路指引,不做深究,有兴趣或有具体需要,可以参照上述源码自己探索实现。
五、学习源码
https://gitee.com/imdongrui/study-repo.git
仓库中的spring-cache工程