共计 4474 个字符,预计需要花费 12 分钟才能阅读完成。
前言
昨天在开发业务时,打算退出缓存层来进步零碎响应速度。查找了一些材料,发现 Spring 的缓存性能非常弱小!只须要增加大量的代码,就能够轻松缓存办法所返回的对象。这篇文章通过形容一个理论应用例子,介绍 Spring Cache 的应用限度以及注意事项。
环境筹备
- Redis 5+
- JDK 1.8+
- Gradle 6+
- 一款你青睐的 IDE
实际过程
增加依赖
关上 build.gradle 文件,增加 Spring Cache 依赖。
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 来改良一波。
应用 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 作为缓存引擎,如果小伙伴想用其余引擎,可自行查阅文档进行配置。
@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 参数。这里先不开展说,上面会集中梳理几种注解以及它们的参数意义。
Spring Cache 注解
Spring Cache 罕用的 5 个注解,别离是:
- @EnableCaching
- @Cacheable
- @CachePut
- @CacheEvict
- @CacheConfig
@EnableCaching
在启动类增加 @EnableCaching 注解让零碎开启缓存性能。
@Cacheable
性能是开启缓存,能够标记在类上或者是办法上。在调用办法时,会先从缓存中获取后果,若不存在再执行办法。主要参数包含 cacheNames、key、condition 和 unless 等。
- cacheNames:用于指定缓存存储的汇合名,必须填写。
- key:缓存对象存储在汇合中的 key 值,缺省依照函数的所有参数组合作为 key 值。
- condition:缓存对象的条件,需应用 SpEL 表达式。只有满足表达式条件的内容才会被缓存。
- unless:缓存对象的条件,需应用 SpEL 表达式。它不同于 condition 参数的中央在于它的判断机会,该条件是在函数被调用之后才做判断的,所以它能够通过对返回对象进行判断。
- keyGenerator:用于指定 key 生成器。若须要自定义 key 生成器,须要实现 KeyGenerator 接口,并应用该参数来指定。
- cacheManager:用于指定应用哪个缓存管理器。
- cacheResolver:用于指定应用那个缓存解析器。
@CachePut
针对办法配置,与 @Cacheable 不同的中央在于它每次都会触发实在办法的调用。简略来说就是更新缓存数据。主要参数和 @Cacheable 统一。
@CacheEvict
针对办法配置,用来从缓存中移除相应数据。除了与 @Cacheable 雷同的参数以外,还有 allEntries 和 beforeInvocation。
- allEntries 非必须,默认为 false。当为 true 时,会移除所有数据。
- beforeInvocation 非必须,默认为 false,会在调用办法之后移除数据。当为 true 时,会在调用办法之前移除数据。
@CacheConfig
该注解是一个类级注解,能够让类上面的办法共享 cacheNames、keyGenerator、cacheManager 和 cacheResolver 参数。
自定义 cacheNames
这里是为了让咱们的缓存注解反对自定义 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 的根本应用形式和罕用注解。后续文章筹备深刻理解其底层原理。
欢送大家关注我的公众号「是然的笔记本」。
再会!