大佬教程收集整理的这篇文章主要介绍了从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
文档:https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/spring-boot-features.html#boot-features-caching
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
支持以下几种缓存实现c;默认自动根据代码依赖判断使用哪种实现c;也可以在配置文件中强制指定使用哪种缓存实现。
在配置类中添加@EnableCaching
来启用缓存功能
@Configuration
@EnableCaching
public class CachingConfig {
}
默认情况下c;如果我们没有明确指定任何其他缓存c;会自动根据依赖环境判断c;如果上图的依赖都没有c;它默认使用COncurrentHashMap作为底层缓存。即
Simple
的类型c;参考代码SimpleCacheconfiguration.java
、ConcurrentMapCacheManager.java
也可以通过配置文件直接指定:
spring:
cache:
type: simple
Cacheable
等。CacheManager
。@Cacheable(value = "user", key = "#id", unless="#result == null")
public User getUser(long id) {...}
cachenames/value:指定缓存组件的名字;将方法的返回结果放在哪个缓存中c;是数组的方式c;可以指定多个缓存。必填
key:缓存的 keyc;可以为空c;如果指定要按照 SpEL 表达式编写c;如果不指定c;则缺省按照方法的所有参数进行组合。
keyGenerator:key的生成器;可以自己指定key的生成器的组件idc;key/keyGenerator:二选一使用。
cacheManager:当自己配置了CacheManager后可以指定使用哪个缓存管理器c;默认使用的是Springboot自动配置的缓存管理器;或者cacheResolver指定获取解析器。
condition:缓存的条件c;可以为空c;使用 SpEL 编写c;返回 true 或者 falsec;只有为 true 才进行缓存.
condition="#userName.length()>2"
。unless:否定缓存;当unless指定的条件为truec;方法的返回值就不会被缓存;可以获取到结果进行判断。
sync:是否开启同步功能c;默认不开启。开启后unless属性将不能使用。
getUser()
将首先检查缓存是否存在c;不存在则调用实际的方法c;最后缓存结果;存在则直接返回缓存结果c;跳过调用实际方法。
或者使用缓存管理器。
@service
public class Userservice {
@Autowired
CacheManager cacheManager;
public User getUser(long id) {
if(cacheManager.containsKey(id)) {
return cacheManager.get(id);
}
// lookup address, cache result, and return it
}
}
指定删除一个或多个或所有值c;以便可以再次将新值加载到缓存中。
@CacheEvict(value="user", ALLENtries=true)
public User updateUser(long id) {...}
ALLENtries
:是否删除所有值。默认falsec;默认情况下c;只删除关联键下的值。注意c;不允许将这个参数设置为true并指定一个键。
beforeInvocation
:默认falsec;是否应该在调用方法之前发生驱逐。将此属性设置为truec;将导致驱逐发生c;而不考虑方法的结果(即c;是否抛出异常)。 默认值为falsec;意味着缓存回收操作将在被建议的方法被成功调用后发生(也就是说c;只有在调用没有抛出异常的情况下)。
或者使用缓存管理器
@Autowired
CacheManager cacheManager;
public void evictSingleCacheValue(String cachename, String cacheKey) {
cacheManager.getCache(cachename).evict(cacheKey);
}
public void evictAllCacheValues(String cachename) {
cacheManager.getCache(cachename).clear();
}
public void evictAllCaches() {
cacheManager.getCachenames().stream()
.forEach(cachename -> cacheManager.getCache(cachename).clear());
}
@CachePut(value="addresses")
public String getAddress(Customer customer) {...}
@Caching(evict = {
@CacheEvict("addresses"),
@CacheEvict(value="directory", key="#customer.name") })
public String getAddress(Customer customer) {...}
可以使用@Caching
将多个缓存注解组合c;使用它来实现我们自己的自定义缓存逻辑。
使用@Cacheconfig
注解c;我们可以在类级别将一些缓存配置简化到一个地方。
@Cacheconfig(cachenames={"addresses"})
public class CustomerDataservice {
@Cacheable
public String getAddress(Customer customer) {...}
Spring Cache提供了一些供我们使用的SpEL上下文数据c;下表直接摘自Spring官方文档:
名称 | 位置 | 描述 | 示例 |
---|---|---|---|
root对象 | 当前被调用的方法名 | #root.methodname | |
root对象 | 当前被调用的方法 | #root.method.name | |
target | root对象 | 当前被调用的目标对象实例 | #root.target |
targetClass | root对象 | 当前被调用的目标对象的类 | #root.targetClass |
args | root对象 | 当前被调用的方法的参数列表 | #root.args[0] |
caches | root对象 | 当前方法调用使用的缓存列表 | #root.caches[0].name |
Argument Name | 执行上下文 | 当前被调用的方法的参数c;如findArtisan(Artisan artisan),可以通过#artsian.id获得参数 | #artsian.id |
result | 执行上下文 | 方法执行后的返回值(仅当方法执行后的判断有效c;如 unless cacheEvict的beforeInvocation=false) | #result |
注意:
1.当我们要使用root对象的属性作为key时我们也可以将“#root”省略c;因为Spring默认使用的就是root对象的属性。 如
@Cacheable(key = "targetClass + methodName +#p0")
2.使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。 如:
@Cacheable(value="users", key="#id")
@Cacheable(value="users", key="#p0")
SpEL提供了多种运算符
类型 | 运算符 |
---|---|
关系 | <c;>c;<=c;>=c;==c;!=c;ltc;gtc;lec;gec;eqc;ne |
算术 | +c;- c;* c;/c;%c;^ |
逻辑 | &&c;||c;!c;andc;orc;notc;betweenc;instanceof |
条件 | ?: (ternary)c;?: (elvis) |
正则表达式 | @H_307_750@matches|
其他类型 | ?.c;?[…]c;![…]c;1c;$[…] |
文档:https://spring.io/projects/spring-data-redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
需要引入commons-pool2作为连接池 必须!!!
<!--spring2.0集成redis所需common-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
版本依赖如下:
使用的Javaredis客户端是Lettuce因为 Spring Boot 默认使用它。
在application.yaml
文件中配置属性:
spring:
cache:
# 指定使用redis
type: redis
redis:
# rEIDs的连接ip
host: 127.0.0.1
port: 6379
password: laker123
# redis默认情况下有16个分片c;这里配置具体使用的分片c;默认是0
database: 0
# 连接超时时间(毫秒)
timeout: 10000ms
# redis client配置c;使用lettuce
lettuce:
pool:
# 连接池中的最小空闲连接 默认 0
@H_323_173@min-idle: 0
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
@H_323_173@max-wait: 1000ms
# 连接池最大连接数(使用负值表示没有限制) 默认 8
@H_323_173@max-active: 8
# 连接池中的最大空闲连接 默认 8
@H_323_173@max-idle: 8
注意注意注意!!!c;这里redis默认的序列化为JDK序列化c;所以上面的User
实体类一定要实现序列化public class User implements @R_607_9464@lizable
c;否则会报java.io.Not@R_607_9464@lizableException
异常。
@Cacheable(value = "user", key = "#id", unless="#result == null")
public User getUser(long id) {...}
getUser(1)
其对应结果如下图:
这里我们后边会修改其默认的序列化为json格式。
框架会自动生成一个redisTemplate
实例 c;我们也可以直接使用redisTemplate
操作缓存。
@Autowired
private redisTemplate redisTemplate;
public void save(User user) {
redisTemplate.opsForValue().set(user.getId(), user);
}
public User findById(Long id) {
return (User)redisTemplate.opsForValue().get(id);
}
redisTemplate 是线程安全的哦
默认情况下c;Lettuce 会为我们管理序列化和反序列化c;我们来自定义配置redisTemplate。
@Configuration
@EnableCaching
public class CachingConfig {
@Bean
public redisTemplate<Object, Object> redisTemplate(redisConnectionFactory factory) {
redisTemplate<Object, Object> redisTemplate = new redisTemplate<>();
redisTemplate.setConnectionFactory(factory);
GenericJackson2Jsonredis@R_607_9464@lizer genericJackson2Jsonredis@R_607_9464@lizer = new GenericJackson2Jsonredis@R_607_9464@lizer();
redisTemplate.setKey@R_607_9464@lizer(genericJackson2Jsonredis@R_607_9464@lizer);
redisTemplate.SETVALue@R_607_9464@lizer(genericJackson2Jsonredis@R_607_9464@lizer);
redisTemplate.setHashKey@R_607_9464@lizer(new Stringredis@R_607_9464@lizer());
redisTemplate.setHashValue@R_607_9464@lizer(genericJackson2Jsonredis@R_607_9464@lizer);
return redisTemplate;
}
}
Jackson2Jsonredis@R_607_9464@lizer和GenericJackson2Jsonredis@R_607_9464@lizer的区别
使用Jackson2Jsonredis@R_607_9464@lizer需要指明序列化的类Classc;可以使用Obejct.class
使用GenericJacksonredis@R_607_9464@lizer比Jackson2Jsonredis@R_607_9464@lizer效率低c;占用内存高。
GenericJacksonredis@R_607_9464@lizer反序列化带泛型的数组类会报转换异常c;解决办法存储以JSON字符串存储。
GenericJacksonredis@R_607_9464@lizer和Jackson2Jsonredis@R_607_9464@lizer都是以JSON格式去存储数据c;都可以作为redis的序列化方式。
来自:https://blog.csdn.net/bai_bug/article/details/81222519
redisTemplate.opsForValue().set(id,user);
回归Cache中redisCacheManager
自定义配置如下:
@Bean
public redisCacheconfiguration cacheconfiguration() {
return redisCacheconfiguration.defaultCacheconfig()
.entryTtl(Duration.ofminutes(60))
.disableCachingNullValues()
.@R_607_9464@lizeValuesWith(@R_607_9464@lizationPair.from@R_607_9464@lizer(new GenericJackson2Jsonredis@R_607_9464@lizer()));
}
@Bean
public redisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
return (builder) -> builder
.withCacheconfiguration("itemCache",
redisCacheconfiguration.defaultCacheconfig()
.entryTtl(Duration.ofminutes(10)))
.withCacheconfiguration("customerCache",
redisCacheconfiguration.defaultCacheconfig()
.entryTtl(Duration.ofminutes(5)));
}
分别为itemCache
和customerCache
配置了 10 分钟和 5 分钟的 TTL 值。
扩展CachingConfigurerSupport
类并覆盖cacheManager
() 方法。此方法返回一个 beanc;它将成为我们应用程序的默认缓存管理器:
@Configuration
@EnableCaching
public class redisConfig extends CachingConfigurerSupport {
@Override
public CacheManager cacheManager() {...}
@Override
public CacheResolver cacheResolver() {...}
@Override
public KeyGenerator keyGenerator() {...}
@Override
public CacheErrorHandler errorHandler() {...}
}
在某些情况下c;我们可能需要在应用程序中使用多个缓存管理器。
配置类中创建两个缓存管理器 bean。配置其中的一个 bean为@PriMary
@Configuration
@EnableCaching
public class @H_468_150@multipleCacheManagerConfig {
@Bean
@PriMary
public CacheManager cacheManager() {
CaffeineCacheManager cacheManager = new CaffeineCacheManager("customers", "orders");
cacheManager.setCaffeine(Caffeine.newBuilder()
.initialCapacity(200)
.@H_277_229@maximumSize(500)
.weakKeys()
.recordStats());
return cacheManager;
}
@Bean
public CacheManager alternateCacheManager() {
return new ConcurrentMapCacheManager("customerorders", "orderprice");
}
}
现在c;Spring Boot 将使用CaffeineCacheManager
作为所有缓存方法的默认值c;直到我们为一个方法明确指定了AlternateCacheManager
@Cacheable(cachenames = "customers")
public Customer getCustomerDetail(Integer customerId) {
return customerDetailRepository.getCustomerDetail(customerId);
}
@Cacheable(cachenames = "customerorders", cacheManager = "alternateCacheManager")
public List<Order> getCustomerorders(Integer customerId) {
return customerDetailRepository.getCustomerorders(customerId);
}
@Configuration
@EnableCaching
public class redisConfig extends CachingConfigurerSupport {
@Bean
public redisTemplate<Object, Object> redisTemplate(redisConnectionFactory factory) {
redisTemplate<Object, Object> redisTemplate = new redisTemplate<>();
redisTemplate.setConnectionFactory(factory);
GenericJackson2Jsonredis@R_607_9464@lizer genericJackson2Jsonredis@R_607_9464@lizer = new GenericJackson2Jsonredis@R_607_9464@lizer();
redisTemplate.setKey@R_607_9464@lizer(genericJackson2Jsonredis@R_607_9464@lizer);
redisTemplate.SETVALue@R_607_9464@lizer(genericJackson2Jsonredis@R_607_9464@lizer);
redisTemplate.setHashKey@R_607_9464@lizer(new Stringredis@R_607_9464@lizer());
redisTemplate.setHashValue@R_607_9464@lizer(genericJackson2Jsonredis@R_607_9464@lizer);
return redisTemplate;
}
@Bean
public CacheManager cacheManager(redisConnectionFactory factory) {
redis@R_607_9464@lizer<String> redis@R_607_9464@lizer = new Stringredis@R_607_9464@lizer();
GenericJackson2Jsonredis@R_607_9464@lizer genericJackson2Jsonredis@R_607_9464@lizer = new GenericJackson2Jsonredis@R_607_9464@lizer();
redisCacheconfiguration config = redisCacheconfiguration.defaultCacheconfig()
.entryTtl(Duration.ofHours(1)) //设置所有缓存有效时间 为 1个小时。
.@R_607_9464@lizeKeysWith(redis@R_607_9464@lizationContext.@R_607_9464@lizationPair.from@R_607_9464@lizer(redis@R_607_9464@lizer))
.@R_607_9464@lizeValuesWith(redis@R_607_9464@lizationContext.@R_607_9464@lizationPair.from@R_607_9464@lizer(genericJackson2Jsonredis@R_607_9464@lizer))
.disableCachingNullValues(); // 禁用缓存空值.
redisCacheManager cacheManager = redisCacheManager.builder(factory).cacheDefaults(config).build();
return cacheManager;
}
}
CaffeineCacheManager
由spring-boot-starter-cache starter 提供。如果依赖存在Caffeinec;它将由 Spring 自动配置c; Caffeine是一个用 Java 8 编写的缓存库。
增加依赖Caffeine
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
可以自己定制配置c;控制缓存行为的主要配置c;例如过期、缓存大小限制等
@Bean
public Caffeine caffeineConfig() {
return Caffeine.newBuilder()
.expireAfterWrite(60, TimeUnit.minutES);
}
@Bean
public CacheManager cacheManager(Caffeine caffeine) {
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
caffeineCacheManager.setCaffeine(caffeine);
return caffeineCacheManager;
}
参考:
… ↩︎
以上是大佬教程为你收集整理的从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器全部内容,希望文章能够帮你解决从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。