获取 IllegalArgumentException:尝试添加包含 AtomicInteger int redis 缓存的数据时无法将 String 转换为 AtomicInteger

Getting an IllegalArgumentException: Cannot convert String to AtomicInteger when trying to add data that contains an AtomicInteger int redis cache

我正在尝试将数据模型添加到 Redis 缓存中。当我取出模型时出现异常

org.springframework.core.convert.ConversionFailedException: Failed to convert from type [byte[]] to type [java.util.concurrent.atomic.AtomicInteger] for value '{53}'; nested exception is java.lang.IllegalArgumentException: Cannot convert String [5] to target class [java.util.concurrent.atomic.AtomicInteger]] with root cause

模特是

@RedisHash(value = "ThottleRate", timeToLive = 5)

public class ThottleRate implements Serializable  {
 
       private static final long serialVersionUID = 1L;

       @Id
       private String url;
       private AtomicInteger rate;

       public ThottleRate(String url, int rate) {
             super();
             this.url = url;
             this.rate = new AtomicInteger(rate);
       }

       public boolean isAllowed(){
           if(this.rate.decrementAndGet() <= 0) {
                    return false;
             }
             return true;
       }

调用代码为

try {
                    option = throttleRateRepository.findById(url);
                    ThottleRate rate = option.get();
                    allow = rate.isAllowed();
             } catch(NoSuchElementException e) {
                throttleRateRepository.save(new ThottleRate(url, 5));
                    allow = true;
             }

我想做的是使用 redis 缓存来限制功能。它有一个生存时间,在此期间可以访问 url 的次数。

但是当调用是

option = throttleRateRepository.findById(url);

这会抛出 IllegalArgumentException

这似乎是最简单的使用redis缓存的方法,有一个生存时间和多个速率

抛出异常是因为 Spring Data Redis 在加载模型时不知道如何将存储在 Redis 中的字节数组反序列化为 AtomicInteger 类型。您需要为此注册一个数据类型转换器。

下面是示例数据类型转换器:

@Component
@ReadingConverter
public class BytesToAtomicIntegerConverter implements Converter<byte[], AtomicInteger> {

  @Override
  public AtomicInteger convert(byte[] source) {
    if (ObjectUtils.isEmpty(source)) {
      return null;
    }

    int n = NumberUtils.parseNumber(
        new String(source, StandardCharsets.UTF_8), Integer.class);
    return new AtomicInteger(n);
  }
}

可以通过将此 bean 添加到 Spring 引导配置来使用 Spring Data Redis 进行注册:

@Bean
public RedisCustomConversions redisCustomConversions(
  BytesToAtomicIntegerConverter converter) {

  return new RedisCustomConversions(List.of(converter));
}

注册数据转换器后,错误就会消失。

在实施此类解决方案时,您必须牢记一些事项。 AtomicInteger 字段用于记录特定人员的请求数。如果有多个服务器为请求提供服务,那么不同的服务器最终将在本地内存中的该字段中存储不同的值。由于与 Redis 的通信需要时间(即使仅在毫秒范围内),因此该值被另一台服务器更新的可能性远非零。如果这种偏差对于用例来说是可以接受的,那么这可能不是问题。

我还建议查看一些可以帮助实现请求限制的现有库。以下是一些示例:

  1. Throttling a Rest API in Java
  2. Rate Limiting a Spring API Using Bucket4j
  3. Implementing Throttling in Java (Spring Boot)