获取 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 的通信需要时间(即使仅在毫秒范围内),因此该值被另一台服务器更新的可能性远非零。如果这种偏差对于用例来说是可以接受的,那么这可能不是问题。
我还建议查看一些可以帮助实现请求限制的现有库。以下是一些示例:
- Throttling a Rest API in Java
- Rate Limiting a Spring API Using Bucket4j
- Implementing Throttling in Java (Spring Boot)
我正在尝试将数据模型添加到 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 的通信需要时间(即使仅在毫秒范围内),因此该值被另一台服务器更新的可能性远非零。如果这种偏差对于用例来说是可以接受的,那么这可能不是问题。
我还建议查看一些可以帮助实现请求限制的现有库。以下是一些示例:
- Throttling a Rest API in Java
- Rate Limiting a Spring API Using Bucket4j
- Implementing Throttling in Java (Spring Boot)