微服务架构Day10-SpringBoot之缓存

SpringBoot与缓存

  • JSR107
  • 搭建缓存基本环境
  • 缓存的使用
  • 缓存的工作原理
      • 自动配置类:
      • 缓存配置类
      • 缓存的运行流程
  • 缓存中间件 Redis
      • 整合Redis缓存
  • 自定义CacheManager

JSR107

Java Caching定义5个核心接口:CachingProvider,CacheManager,Cache,Entry,Expiry

  • CachingProvider:定义了创建,配置,获取,管理和控制多个CacheManager.一个应用可以在运行期间访问多个CachingProvider
  • CacheManager:定义了创建,配置,获取,管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中,一个CacheManager仅被一个CacheProvider所拥有
  • Cache:是一个类似Map的数据结构并临时存储以key为索引的值,一个Cache仅被一个CacheManager所拥有
  • Entry:是一个存储在Cache中的key-value键值对
  • Expiry:每一个存储在Cache中的条目有一个定义的有效期,一旦超过这个时间,条目为过期状态.一旦过期,条目将不可访问,更新和删除.缓存有效期可以通过ExpiryPolicy设置
<dependency>
	<groupId>javax.cachegroupId>
	<artifactId>cache-apiartifactId>
dependency>

搭建缓存基本环境

1.导入数据库文件,创建,创建表
2.创建javabean封装数据
3.整合MyBatis操作数据库
	1.配置数据源信息
	2.使用Mybatis,创建数据库操作语句

缓存的使用

  • 步骤
1.开启基于注解的缓存 		@EnableCaching
2.标注缓存注解		
  • 缓存重要概念
    • Cache: 缓存接口,定义缓存操作.实现有:RedisCache,EhCacheCache,ConcurrentMapCache
    • CacheManager: 缓存管理器,管理各种缓存组件
    • keyGenerator: 缓存数据时key生成策略
    • serialize: 缓存数据时value序列化策略
  • 缓存注解
    • @Cacheable: 主要针对方法配置,根据方法的请求参数对结果进行缓存:以后再要相同的数据,直接从缓存中获取,不再调用方法
    属性:
    	cacheNames/value:指定缓存组件的名字,将方法的返回结果放在缓存中,是数组的方式,可以指定多个缓存(CacheManager管理多个Cache组件,对缓存的真正CRUD操作在Cache组件中,每一个缓存组件有自己唯一一个名字)
    	key:缓存数据使用的key,可以用key指定键值,默认使用方法参数的值(SpEL:methodName(当前被调用的方法名),
    																  method(当前被调用的方法),
    																  target(当前被调用的目标对象),
    																  targetClass(当前被调用的目标对象类),
    																  args(当前被调用的方法参数列表),
    																  caches(当前方法调用使用的缓存列表),
    																  argument name(方法参数的名字-#参数),
    																  result(方法执行后的结果返回值))
    	keyGenerator:key的生成器,可以指定key的生成器组件.
        cacheManager:指定缓存管理器,
        cacheResolver:指定缓存解析器,和缓存管理器一样
        condition:指定符合条件的情况下才进行缓存
        unless:否定缓存-当unless指定的条件为true,方法的返回值就不会缓存.可以获取到结果进行判断
        sysnc:是否使用异步模式,不支持unless属性
    
    	key和keyGenerator只要出现一个
    	cacheManager和cacheResolver只要出现一个
    
    • @CacheEvict: 清空缓存
    • @CachePut: 保证方法被调用,结果被缓存,更新缓存数据
    • @EnableCaching: 开启基于注解的缓存

缓存的工作原理

默认使用的是ConcurrentMapCache组件中的CacheManager进行缓存的,将数据保存在 ConcurrentMap

自动配置类:

org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration

缓存配置类

org.springframework.boot.autoconfigure.cache.GenericCacheConfiguration
org.springframework.boot.autoconfigure.cache.JCacheCacheConfiguration	(JSR107)
org.springframework.boot.autoconfigure.cache.EhCacheCacheConfiguration
org.springframework.boot.autoconfigure.cache.HazelcastCacheConfiguration
org.springframework.boot.autoconfigure.cache.InfinispanCacheConfiguration
org.springframework.boot.autoconfigure.cache.CouchbaseCacheConfiguration
org.springframework.boot.autoconfigure.cache.RedisCacheConfiguration
org.springframework.boot.autoconfigure.cache.CaffeineCacheConfiguration
org.springframework.boot.autoconfigure.cache.SimpleCacheConfiguration
org.springframework.boot.autoconfigure.cache.NoOpCacheConfiguration
  • 默认SimpleCacheConfiguration生效:
    1.给容器中注册CacheManager:ConcurrentMapCacheManager
    2.ConcurrentMapCacheManager可以获取和创建ConcurrentMapCache类型的缓存组件
    3.ConcurrentMapCache的作用是将数据保存在ConcurrentMap中

缓存的运行流程

  • @Cacheable
    • 方法运行之前,CacheManager先获取相应的缓存,按照CacheNames指定的名字获取,第一次获取缓存如果没有Cache组件会自动创建缓存组件
    • 在Cache中使用key查找缓存内容,key是通过KeyGenerator生成的,默认就是方法的参数
      SimpleKeyGenerator生成key的策略:
      1.如果没有参数: key=new SimpleKey()
      2.如果有一个参数: key=参数的值
      3.如果有多个参数: key=new SimpleKey(params)    
      
    • 如果没有查到缓存内容就会调用目标方法
    • 将目标方法返回的结果,放进缓存中
      @Cacheable标注的方法执行之前先检查缓存中是否有缓存数据,默认按照参数值作为key去查询缓存,如果没有就运行方法,并将结果放入缓存中
  • 流程核心:
    • 使用CacheManager(ConcurrentMapCacheManager)按照CacheNames指定的名字获取Cache(ConcurrentMapCache)组件
    • key是使用keyGenerator生成的,默认使用SimpleKeyGenerator生成key

  • @CachePut
    既调用方法,又更新缓存数据(对数据库修改操作,会将结果保存在缓存中)
    • 运行流程:
      • 先调用目标方法
      • 再将方法的结果放到缓存中
    在运行过程中,执行完@CachePut的方法,查询的结果还是之前的数据 :
    - 因为在没有指定key值的情况下,key值默认是方法的参数.
    - 当方法的参数值不同时,Cache根据key查询缓存数据,key值对应的数据并没有更新.
    - 如果需要同步更新缓存数据,需要指定为相同的key值,缓存中的数据才会更新
    
    - 在@Cacheable中不能像@CachePut中使用result属性,
    - 因为在@Cacheable是先判断注解,此时没有result值,而在@CachePut是先执行方法
    

  • @CacheEvict
    清空缓存:当数据库中数据被删除时,执行删除缓存中的数据
    • 通过key指定要清楚的缓存数据
    • allEntries: 是否清除这个缓存中所有数据
    • beforeInvocation: 是否在方法执行之前清除缓存中的数据

  • @Caching
    • 定义复杂的缓存规则
    • 如果在定义的复杂缓存规则中有 @CachePut 或则 @CacheEvict(beforInvocation=true) ,这个注解就是在目标方法执行后执行
    @Caching(
              cacheable = {
                      @Cacheable(value = "emp",key = "#emp.lastName"),
                      @Cacheable(value = "emp",key = "#emp.id")
              },
              put = {
                      @CachePut(value = "emp",key = "#emp.lastName"),
                      @CachePut(value = "emp",key = "#emp.id")
              },
              evict = {
                      @CacheEvict(value = "emp",key = "#emp.lastName"),
                      @CacheEvict(value = "emp",key = "#emp.id")
              }
      )
    

    • @CacheConfig
      • 配置缓存中的所有的公共配置

缓存中间件 Redis

  • Redis: Redis是一个开源的内存中的数据结构存储系统,可以用作数据库,缓存消息中间件
  • 操作工具:Redis Desktop Manager

整合Redis缓存

  • 在pom.xml中引入redis依赖
<dependency>
       <groupId>org.springframework.bootgroupId>
       <artifactId>spring-boot-starter-data-redisartifactId>
dependency>
  • 配置redis,在application.properties中配置redis
spring.redis.host=192.168.32.242
  • RedisTemplate:(操作k-v都是对象)
@Bean
    @ConditionalOnMissingBean(
        name = {"redisTemplate"}
    )
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
  • 保存对象时,使用JDK的序列化机制,将序列化后的数据保存到redis
  • 为了增强Redis数据库中的数据可读性:
    • 将对象数据以json方式保存:
      • 将对象转化为json
      • 配置redisTemplate的json序列化规则
   @Configuration
public class MyRedisConfig {
 @Bean
 public RedisTemplate<Object, Employee> empRedisTemplate(RedisConnectionFactory redisConnectionFactory){
     RedisTemplate<Object,Employee> redisTemplate=new RedisTemplate<Object,Employee>();
     redisTemplate.setConnectionFactory(redisConnectionFactory);
     Jackson2JsonRedisSerializer<Employee> serializer = new Jackson2JsonRedisSerializer<Employee>(Employee.class);
     redisTemplate.setDefaultSerializer(serializer);
     return redisTemplate;
 }
}
Redis常见的数据类型:
	String-字符串
	List-列表
	Set-集合
	Hash-散列
	ZSet-有序集合

redisTemplate.opsForValue()--String(字符串)
redisTemplate.opsForList()--List(列表)
redisTemplate.opsForSet()--Set(集合)
redisTemplate.opsForHash()--Hash(散列)
redisTemplate.opsForZSet()--ZSet(有序集合)
  • StringRedisTemplate(操作k-v都是字符串)
    在RedisAutoConfiguration中:
@Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

在StringRedisTemplate中:

public class StringRedisTemplate extends RedisTemplate<String, String> {
    public StringRedisTemplate() {
        this.setKeySerializer(RedisSerializer.string());
        this.setValueSerializer(RedisSerializer.string());
        this.setHashKeySerializer(RedisSerializer.string());
        this.setHashValueSerializer(RedisSerializer.string());
    }

    public StringRedisTemplate(RedisConnectionFactory connectionFactory) {
        this();
        this.setConnectionFactory(connectionFactory);
        this.afterPropertiesSet();
    }

    protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
        return new DefaultStringRedisConnection(connection);
    }
}
Redis常见的数据类型:
	String-字符串
	List-列表
	Set-集合
	Hash-散列
	ZSet-有序集合

stringRedisTemplate.opsForValue()--String(字符串)
stringRedisTemplate.opsForList()--List(列表)
stringRedisTemplate.opsForSet()--Set(集合)
stringRedisTemplate.opsForHash()--Hash(散列)
stringRedisTemplate.opsForZSet()--ZSet(有序集合)

自定义CacheManager

  • CacheManagerCustomizers: 定制缓存规则
  • 可以在方法中使用缓存管理器获取缓存,调用操作API对缓存中的数据进行操作

你可能感兴趣的:(架构)