<!-- Space: qifu -->
<!-- Parent: 后端技术&知识&规范 -->
<!-- Parent: 技术方案 -->
<!-- Parent: 基建 -->
<!-- Parent: 00-基础组件 -->
<!-- Title: 20250411-EngineStarterRedis使用指南 -->

<!-- Macro: :anchor\((.*)\):
     Template: ac:anchor
     Anchor: ${1} -->
<!-- Macro: \!\[.*\]\((.+)\)\<\!\-\- width=(.*) \-\-\>
     Template: ac:image
     Url: ${1}
     Width: ${2} -->
<!-- Macro: \<\!\-\- :toc: \-\-\>
     Template: ac:toc
     Printable: 'false'
     MinLevel: 2 
     MaxLevel: 4 -->
<!-- Include: 杂项/声明文件.md -->

<!-- :toc: -->

# engine-starter-redis 使用教程

> 基于 Redis 的各种工具封装  
> 具体使用可参考 [engine-sample > engine-sample-starter-redis](../engine-sample/engine-sample-starter-redis)  
> 版本要求：`$verison >= 1.0.14-SNAPSHOT`

## 功能特性

- [X] `@YmIdempotent`: 基于 Redis 的幂等工具
- [X] `@YmRateLimit`: 基于 Redisson 的限流工具
- [X] `@Lock4j`: 基于 Lock4j 的分布式锁工具
    - [X] 旧包中的 `@DistributedMultiLock` 慢慢迁移到新注解
    - [X] TODO 旧包中的 `@DistributedMultiLock` 需要实现 `@Lock4jMulti`
- [X] `@Cacheable`: 基于 Redis 的 SpringCache 集成
    - [X] 扩展 key，支持 key 中自定义时间 `abc#1000`
- [X] `YmRedisClient`: Redis 操作工具类，基于 `StringRedisTemplate`
- [X] `YmCacheClient`: Redis 缓存操作类
- [X] `YmIdempotentManager`: 幂等管理类
- [X] `YmRateLimitManager`: 限流管理类
- [X] `YmRedisKeyUtils`: Redis key 构建工具
- [X] `YmRedisLockClient`: 基于 Redisson 的分布式锁工具
- [X] `YmRedisMessageListener`: Redis 消息监听类，实现该类就可以实现消息监听

-------

## 快速使用

### 添加依赖

**注意：** `qifu-saas-parent` 版本需要高于 `1.0.14-SNAPSHOT`

```xml

<dependency>
    <groupId>com.yuanmeng.engine</groupId>
    <artifactId>engine-starter-redis</artifactId>
</dependency>
```

### 使用工具

除了 spring-cache 和 RedisMessageListener 默认关闭之外，别的功能都是默认开启的，开箱即用

#### 幂等工具使用

```java
public class Usage {

    // 生成token请使用：idempotentManager.token("token");

    @YmIdempotent(key = "#token", type = YmIdempotentType.TOKEN)
    public String tokenTest(String token) {
        log.info("tokenTest:{}", token);
        return "success";
    }
}
```

#### 限流工具使用

```java
public class Usage {
    @YmRateLimit(key = "#id", timeUnit = RateIntervalUnit.HOURS, count = 5)
    public String rateLimitHour(String id) {
        log.info("rateLimitHour: {}", id);
        return "success";
    }
}
```

#### 分布式锁工具使用

```java
public class Usage {
    @Autowired
    private LockTemplate lockTemplate;

    @Lock4j(name = "lock", keys = "#key", acquireTimeout = 1000)
    public String lockAcquireFail(String key) throws InterruptedException {
        log.info("lockAcquireFail: {}", key);
        Thread.sleep(3000);
        return "success";
    }

    // 多锁模式一
    @Lock4jMulti(name = "lockMulti", keyList = "#keys")
    public String lockMulti(List<String> keys) throws InterruptedException {
        log.info("lockMulti: {}", key);
        Thread.sleep(3000);
        return "success";
    }

    // 多锁模式二
    @Lock4jMulti(
            value = {
                    @Lock4j(name = "lock", keys = "#key"),
                    @Lock4j(name = "lock", keys = "#key + '_123'")
            }
    )
    public String lockMultiSecond(String key) throws InterruptedException {
        log.info("lockMultiSecond: {}", key);
        Thread.sleep(3000);
        return "success";
    }

    public String lockTemplate(String key) throws InterruptedException {
        LockInfo lock = lockTemplate.lock(key);
        if (lock == null) {
            throw new RuntimeException("lock fail");
        }
        try {
            log.info("lockTemplate: {}", key);
            Thread.sleep(2000);
        } finally {
            lockTemplate.releaseLock(lock);
        }

        return "success";
    }
}
```

#### 缓存工具使用

##### 开启Redis缓存

```yaml
yuanmeng:
  redis:
    cache-manager:
      enable: true
```

##### 使用缓存工具

```java
public class Usage {
    @Cacheable(cacheNames = "cache:cacheByUser", key = "#user.id + '#' + #expires")
    public User cacheByIdWithExpires(User user, Integer expires) throws InterruptedException {
        Thread.sleep(5000);
        log.info("执行了cacheByIdWithExpires方法: {}, expires = {}", user.getId(), expires);
        return user;
    }
}
```

#### RedisMessageListener工具使用

##### 开启Redis消息

```yaml
yuanmeng:
  redis:
    redis-message-listener:
      enable: true
```

##### 使用消息工具

```java

@Slf4j
@Component
public class RedisMessageListenerUsage extends YmRedisMessageListener {

    public static final String TOPIC = "test_topic";

    @Override
    public String topic() {
        return TOPIC;
    }

    @Override
    public boolean enable() {
        return true;
    }

    @Override
    protected void onMessage(YmPublishWrapper messageBody, Message message, byte[] pattern) {
        log.info("接收消息: {}", JSONObject.toJSONString(messageBody));
        log.info("接收消息体：{}", JSONObject.toJSONString(messageBody.getData()));
        log.info("接收消息体类型：{}", JSONObject.toJSONString(messageBody.getData().getClass().getName()));
        log.info("接收消息Pattern：{}", new String(pattern));
    }

}
```

------

## 完整默认配置文件

```yaml
yuanmeng:
  redis:
    #- 开启 engine-redis-starter
    enable: true
    #- 开启全局默认前缀
    enable-prefix: false
    #- 全局默认前缀
    prefix: sample
    #- 开启 YmRedisClient 工具类
    enable-redis-client: true
    #- Redisson 相关配置
    redisson:
      enable: true
      enable-codec: true
      enable-prefix: false
      prefix: sample_redisson
    #- RedisMessageListener 相关配置
    redis-message-listener:
      enable: false
      core-pool-size: 5
      max-pool-size: 10
      queue-capacity: 1000
      listeners:
      #-  - com.yuanmeng.sample.starter.redis.message.RedisMessageListenerUsage
    #- Spring Redis 缓存配置
    cache-manager:
      enable: false
      default-cache-seconds: 3600
      default-cache-null-seconds: 600
      cache-seconds-map:
      #-  '[cache:simpleDefaultExpires]': 5000
      cache-null-seconds-map:
      #-  '[cacheNull:simpleDefaultExpires]': 1200
    #- 幂等配置
    idempotent:
      enable: true
      enable-prefix: true
      prefix: idempotent
    #- 限流配置
    rate-limit:
      enable: true
      enable-prefix: true
      prefix: rate_limit
    #- Lock4j Redisson 分布式锁配置
    lock4j-redisson:
      enable: false
```
