# 使用介绍

## 配置文件:
```yml
spring:
  redis:
    database: 0
    host: r-xxxx.redis.rds.aliyuncs.com
    password: xxxx
    port: 6379
    timeout: 2s
    elab:
      # 注解的统一超时时间
      ttl: 30
      # 注解的统一前缀
      prefix-with: user_
      config-refresh:
      	enable: true # 是否开启配置中心功能
      	config-refresh-cacheKey: config-refresh # 配置更新的缓存的key
      	config--push-cache-key: aaa # 缓存推送的topic的key
      	default-config: # 预先设置一些默认值，可以通过redis动态修改
      		A: A
      		B: B
```

## 使用类
### CacheTemplate
该类一共有个两个属性: `RedissonClient`、`RedisTemplate`

分别应用到分布式锁以及普通的对象操作。

关于分布式锁的应用简单使用案例
```java
@Autowired
private CacheTemplate cacheTemplate;
/**
 * 同步和异步
 */
@Test
public void testApp() throws Exception {
    RAtomicLong longObject = RLock xxx = cacheTemplate.getRedissonClient().getAtomicLong("myLong");
    // 同步执行方式
    longObject.compareAndSet(3, 401);
    // 异步执行方式
    RFuture<Boolean> result = longObject.compareAndSetAsync(3, 401);
    Boolean isLock = result.get();
}
```

针对原子性的操作[参考](https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8)

# 针对SpringCache注解使用介绍
##  开启注解
 `@EnableCaching `
**常用注解**

- `@Cacheable`：触发操作将数据保存到缓存中，参数value指cacheName
- `@CacheEvict`：触发操作将数据从缓存中删除（运用于失效模式）
- `@CachePut`：不影响方法执行更新（运用于双写模式）
- `@Caching`：组合以上多个操作
- `@CacheConfig` ：再类级别上共享有关缓存的配置

  **默认配置**

- key自动生成：缓存名字::SimpleKey[]
- value默认是jdk序列化
- 默认ttl时间：-1
- 默认查询数据如果缓存中存在，则不再调用方法，**直接将缓存中命中的数据返回**

### Cacheable

属性介绍:

####  **sync** 

 在多线程环境下，某些操作可能使用相同参数同步调用。默认情况下，缓存不锁定任何资源，可能导致多次计算，而违反了缓存的目的。对于这些特定的情况，属性 sync 可以指示底层将缓存锁住，使只有一个线程可以进入计算，而其他线程堵塞，直到返回结果更新到缓存中。 

```java
@Cacheable(cacheNames="foos", sync="true")
```

####  **condition** 

 有时候，一个方法可能不适合一直缓存（例如：可能依赖于给定的参数）。属性condition支持这种功能，通过SpEL 表达式来指定可求值的boolean值，为true才会缓存（在方法执行之前进行评估）。 

```java
@Cacheable(cacheNames="book", condition="#name.length < 32")
```

此外，还有一个unless 属性可以用来是决定是否添加到缓存。与condition不同的是，unless表达式是在方法调用之后进行评估的。如果返回false，才放入缓存（与condition相反）。 #result指返回值 例：

```java
@Cacheable(cacheNames="book", condition="#name.length < 32", unless="#result.name.length > 5"")
```

### CacheEvict

 spring cache不仅支持将数据缓存，还支持将缓存数据删除。此过程经常用于从缓存中清除过期或未使用的数据。 
@CacheEvict要求指定一个或多个缓存，使之都受影响。此外，还提供了一个额外的参数allEntries 。表示是否需要清除缓存中的所有元素。默认为false，表示不需要。当指定了allEntries为true时，Spring Cache将忽略指定的key。有的时候我们需要Cache一下清除所有的元素。 

```java
@CacheEvict(cacheNames="books", allEntries=true)
```

清除操作默认是在对应方法成功执行之后触发的，即方法如果因为抛出异常而未能成功返回时也不会触发清除操作。使用beforeInvocation可以改变触发清除操作的时间，当我们指定该属性值为true时，Spring会在调用该方法之前清除缓存中的指定元素。

```java
@CacheEvict(cacheNames="books", beforeInvocation=true)
```


## 内置自定义注解
#### CacheLoopSubmit 
同一时刻，只能有一个相匹配的key被访问！
注解字段描述:
- cacheName : 自定义的缓存名字，如果为空默认方法名+参数名
- unionKey  : 唯一的key,重复提交的关键线索,会根据填写的参数名称去获取对应的值作为缓存关键key,如果匹配则认为重复提交.
  
    -[0] : 代表第0个参数
    
    -{text}  : 代表实体对象参数的参数名称

> 参考案例 [0]{text} 表示第0个参数的text属性
- isWaitComplete : 这个代表如果遇到匹配重复提交的情况,是阻塞等待占用线程释放后继续,还是直接跳过.
- errorMsg : 一旦匹配重复提交的规则,返回的错误信息

```java
@CacheLoopSubmit(unionKey = "[0]{text}", cacheName = "demo", timeOut = 10)
public String submit(SomeObject text) throws Exception {
    count--;
    Thread.sleep(500);
    logger.info(text + " 抢到一个资源 ， 资源池  " + count);
    return text.getText();
}
```
- [0] 代表第0个参数
- {text} : 代表对象的属性

# redis配置中心使用介绍



```yaml
# 开启配置刷新功能
spring.redis.elab.config-refresh.enable: true
```

此时会注册 : `RedisRefreshConfigure` 配置

大概流程图:

![image-20210901172831387](https://gitee.com/liukaixiong/drawing-bed/raw/master/image/image-20210901172831387.png)

#### RefreshConfigScopeRegistry

负责注册scope，并且还持有BeanDefinitionRegistry容器作为后续注册对象

#### RedisConfigRefreshCallback

比较核心的类，里面主要拥有一些比较核心的功能：

- 刷新配置
- 创建独立的环境配置,这些配置的优先级会非常高，优先从这个配置里面获取
- 刷新容器,先销毁相关Scope的Bean，然后重新创建

注意的是需要被刷新的Bean一定是拥有了Scope的标记的

```java
// 在类上加入该注解,代表这个类会随着容器的刷新而重载
@Scope(CacheConstants.REFRESH_CONFIG_SCOPE_NAME)
```

通过修改redis的特定的key -> `spring.redis.elab.config-refresh.config--push-cache-key` 发送任意消息便会触发监听的回调

```shell
publish test-redis-* xxx
```

一旦产生回调之后，便会重构相关scope的属性以及相关的bean..

















