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

Posted

技术标签:

【中文标题】获取 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 【发布时间】:2022-01-05 09:44:13 【问题描述】:

我正在尝试将数据模型添加到 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 缓存的最简单方法,具有生存时间和多个速率

【问题讨论】:

【参考方案1】:

抛出异常是因为 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 添加到 SpringBoot 配置中来向 Spring Data Redis 注册:

@Bean
public RedisCustomConversions redisCustomConversions(
  BytesToAtomicIntegerConverter converter) 

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

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

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

我还建议查看一些有助于实现请求限制的现有库。下面是一些例子:

    Throttling a Rest API in Java Rate Limiting a Spring API Using Bucket4j Implementing Throttling in Java (Spring Boot)

【讨论】:

非常感谢您的回答以及有关节流的更多信息。我确实看过他们。但是我之所以这样做是因为 URL 是一个参数,在一个对象中,测试节流,然后使用 URL 调用。

以上是关于获取 IllegalArgumentException:尝试添加包含 AtomicInteger int redis 缓存的数据时无法将 String 转换为 AtomicInteger的主要内容,如果未能解决你的问题,请参考以下文章

插件 [ingest-geoip] 是为 Elasticsearch 6.2.4 版构建的,但 6.5.0 版正在运行

js如何获取某一个元素,如果获取不到就继续获取,直到获取到后停止获取?

iOS ---------- 获取设备的各种信息

java反射获取属性值

Shell 获取路径

iOS 获取文件大小