编程语言   发布时间:2022-06-27  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

文章目录

    • SpringBoot集成缓存Cache
      • 1.增加pom依赖
      • 2.启用缓存功能
    • 常见缓存操作
      • 缓存
      • 清除缓存
      • 更新缓存
      • 组合缓存
      • 类缓存配置
      • SpEL上下文数据
    • Cache实现之redis缓存管理器
      • 方式一 redisCacheconfiguration
      • 方式二 redisCacheManagerBuilderCustomizer
      • 方式三 CachingConfigurerSupport
      • 配置多个缓存管理器并动态切换
      • 整体示例
    • Cache实现之Caffeine缓存管理器

SpringBoot集成缓存Cache

文档:https://docs.spring.io/spring-boot/docs/2.3.12.RELEASE/reference/html/spring-boot-features.html#boot-features-caching

1.增加pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-cache</artifactId>
</dependency>

支持以下几种缓存实现࿰c;默认自动根据代码依赖判断使用哪种实现࿰c;也可以在配置文件中强制指定使用哪种缓存实现。

从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器

当然也可以自实现 cacheManager࿰c;便参照simple或者redis如何实现即可。

2.启用缓存功能

在配置类中添加@EnableCaching来启用缓存功能

@Configuration
@EnableCaching
public class CachingConfig {
}

默认情况下࿰c;如果我们没有明确指定任何其他缓存࿰c;会自动根据依赖环境判断࿰c;如果上图的依赖都没有࿰c;它默认使用COncurrentHashMap作为底层缓存。即Simple的类型࿰c;代码SimpleCacheconfiguration.javaConcurrentMapCacheManager.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:缓存的 key࿰c;可以为空࿰c;如果指定要按照 SpEL 表达式编写࿰c;如果不指定࿰c;则缺省按照方法的所有参数进行组合。

keyGenerator:key的生成器;可以自己指定key的生成器的组件id࿰c;key/keyGenerator:二选一使用。

cacheManager:当自己配置了CacheManager后可以指定使用哪个缓存管理器࿰c;默认使用的是Springboot自动配置的缓存管理器;或者cacheResolver指定获取解析器。

condition:缓存的条件࿰c;可以为空࿰c;使用 SpEL 编写࿰c;返回 true 或者 false࿰c;只有为 true 才进行缓存. condition="#userName.length()>2"

unless:否定缓存;当unless指定的条件为true࿰c;方法的返回值就不会被缓存;可以获取到结果进行判断。

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:是否删除所有值。默认false࿰c;默认情况下࿰c;只删除关联键下的值。注意࿰c;不允许将这个参数设置为true并指定一个键。

beforeInvocation:默认false࿰c;是否应该在调用方法之前发生驱逐。将此属性设置为true࿰c;将导致驱逐发生࿰c;而不虑方法的结果(即࿰c;是否抛出异常)。

​ 默认值为false࿰c;意味着缓存回收操作将在被建议的方法被成功调用后发生(也就是说࿰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());
}

更新缓存

实际我们不用这个c;高并发下会导致更新丢失问题或者锁问题。这里仅做介绍哈

@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) {...}

SpEL上下文数据

Spring Cache提供了一些供我们使用的SpEL上下文数据࿰c;下表直接摘自Spring官方文档:

@H_307_750@methodName@H_307_750@method
名称位置描述示例
root对象当前被调用的方法名#root.methodname
root对象当前被调用的方法#root.method.name
targetroot对象当前被调用的目标对象实例#root.target
targetClassroot对象当前被调用的目标对象的类#root.targetClass
argsroot对象当前被调用的方法的参数列表#root.args[0]
cachesroot对象当前方法调用使用的缓存列表#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提供了多种运算符

@H_307_750@matches
类型运算符
关系<࿰c;>࿰c;<=࿰c;>=࿰c;==࿰c;!=࿰c;lt࿰c;gt࿰c;le࿰c;ge࿰c;eq࿰c;ne
算术+࿰c;- ࿰c;* ࿰c;/࿰c;%࿰c;^
逻辑&&࿰c;||࿰c;!࿰c;and࿰c;or࿰c;not࿰c;between࿰c;instanceof
条件?: (ternary)࿰c;?: (elvis)
正则表达式
其他类型?.࿰c;?[…]࿰c;![…]࿰c;1c;$[…]

Cache实现之redis缓存管理器

文档: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>

版本依赖如下

从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器

使用的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@lizablec;否则会报java.io.Not@R_607_9464@lizableException异常。

@Cacheable(value = "user", key = "#id", unless="#result == null")
public User getUser(long id) {...}

getUser(1)其对应结果如下图:

从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器

这里我们后边会修改其默认的序列化为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需要指明序列化的类Class࿰c;可以使用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实战Simple、Caffeine和Redis多缓存管理器

回归Cache中redisCacheManager自定义配置如下:

方式一 redisCacheconfiguration

@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()));
}

方式二 redisCacheManagerBuilderCustomizer

@Bean
public redisCacheManagerBuilderCustomizer redisCacheManagerBuilderCustomizer() {
    return (builder) -> builder
      .withCacheconfiguration("itemCache",
        	redisCacheconfiguration.defaultCacheconfig()
                              .entryTtl(Duration.ofminutes(10)))
      .withCacheconfiguration("customerCache",
        	redisCacheconfiguration.defaultCacheconfig()
                              .entryTtl(Duration.ofminutes(5)));
}

分别为itemCachecustomerCache配置了 10 分钟和 5 分钟的 TTL 值。

方式三 CachingConfigurerSupport

扩展CachingConfigurerSupport类并覆盖cacheManager () 方法。此方法返回一个 bean࿰c;它将成为我们应用程序的默认缓存管理器:

@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;
    }
}

Cache实现之Caffeine缓存管理器

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;
}


  1. … ↩︎

大佬总结

以上是大佬教程为你收集整理的从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器全部内容,希望文章能够帮你解决从零开发短视频电商 缓存Cache实战Simple、Caffeine和Redis多缓存管理器所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。