昨天在开发业务时,打算加入缓存层来提升系统响应速度。查找了一些资料,发现 Spring 的缓存功能十分强大!只须要添加少许的代码,就能够轻松缓存方法所返回的对象。这篇文章经过描述一个实际使用例子,介绍 Spring Cache 的使用限制以及注意事项。redis
打开 build.gradle 文件,添加 Spring Cache 依赖。spring
implementation 'org.springframework.boot:spring-boot-starter-cache'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
复制代码
@Data
@AllArgsConstructor
public class Post implements Serializable {
private Long id;
private String title;
private String content;
}
复制代码
PS:这里使用到了 Lombok 插件,若是不熟悉可先查询相关资料进行了解。数据库
public interface PostRepository {
Post getById(Long id);
}
复制代码
@Component
public class PostRepositoryImpl implements PostRepository {
@Override
public Post getById(Long id) {
// 模拟查询时间
simulateSlowService();
return new Post(100L, "title", "content");
}
private void simulateSlowService() {
try {
Long time = 3000L;
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
复制代码
@RestController
public class PostController {
private final PostRepository postRepository;
public PostController(PostRepository postRepository) {
this.postRepository = postRepository;
}
@GetMapping("posts/{id}")
public Post getPostById(@PathVariable("id") Long id) {
return postRepository.getById(id);
}
}
复制代码
针对一些不容易被修改的资源,若是每次都须要到持久化数据库中进行查询,无疑是十分浪费的,体验也差,下面咱们使用 Spring Cache 来改进一波。数组
@EnableCaching
@SpringBootApplication
public class CacheApplication {
public static void main(String[] args) {
SpringApplication.run(CacheApplication.class, args);
}
}
复制代码
添加 @EnableCaching 注解启动 Spring Cache。缓存
spring:
cache:
type: redis
redis:
host: 127.0.0.1
port: 6379
复制代码
这里用 Redis 做为缓存引擎,若是小伙伴想用其余引擎,可自行查阅文档进行配置。markdown
@RestController
public class PostController {
private final PostRepository postRepository;
public PostController(PostRepository postRepository) {
this.postRepository = postRepository;
}
@Cacheable(cacheNames = "getPostById", key = "#id")
@GetMapping("posts/{id}")
public Post getPostById(@PathVariable("id") Long id) {
return postRepository.getById(id);
}
}
复制代码
使用 @Cacheable 注解 getPostById 方法,使用了 cacheNames 和 key 参数。这里先不展开说,下面会集中梳理几种注解以及它们的参数意义。app
Spring Cache 经常使用的 5 个注解,分别是:less
在启动类添加 @EnableCaching 注解让系统开启缓存功能。ide
功能是开启缓存,能够标记在类上或者是方法上。在调用方法时,会先从缓存中获取结果,若不存在再执行方法。主要参数包括 cacheNames、key、condition 和 unless 等。函数
针对方法配置,与 @Cacheable 不一样的地方在于它每次都会触发真实方法的调用。简单来讲就是更新缓存数据。主要参数和 @Cacheable 一致。
针对方法配置,用来从缓存中移除相应数据。除了与 @Cacheable 相同的参数之外,还有 allEntries 和 beforeInvocation。
该注解是一个类级注解,可让类下面的方法共享 cacheNames、keyGenerator、cacheManager 和 cacheResolver 参数。
这里是为了让咱们的缓存注解支持自定义 TTL 失效时间,相似下面这种效果。
// 3600 秒后缓存集合自动过时
@Cacheable(cacheNames = "getPostById#3600", key = "#id")
复制代码
为了实现这种效果,咱们建立一个 CustomRedisCacheManager 自定义类,以下所示。
public class CustomRedisCacheManager extends RedisCacheManager {
public CustomRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) {
super(cacheWriter, defaultCacheConfiguration);
}
@Override
protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) {
String[] array = StringUtils.delimitedListToStringArray(name, "#");
name = array[0];
if (array.length > 1) {
long ttl = Long.parseLong(array[1]);
cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl));
}
return super.createRedisCache(name, cacheConfig);
}
}
复制代码
使用自定义 CustomRedisCacheManager 配置 CacheConfig。
public class CacheConfig extends CachingConfigurerSupport {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private Integer redisPort;
@Value("${spring.redis.database}")
private Integer redisDatabase;
@Override
@Bean
public CacheManager cacheManager() {
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofDays(1))
.computePrefixWith(cacheName -> "caching:" + cacheName);
return new CustomRedisCacheManager(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory()), defaultCacheConfig);
}
@Bean
public RedisConnectionFactory redisConnectionFactory() {
RedisStandaloneConfiguration configuration = new RedisStandaloneConfiguration();
configuration.setHostName(redisHost);
configuration.setPort(redisPort);
configuration.setDatabase(redisDatabase);
return new LettuceConnectionFactory(configuration);
}
}
复制代码
本文主要介绍了 Spring Cache 的基本使用方式和经常使用注解。后续文章准备深刻了解其底层原理。