我是Micronaut的新手。我正在尝试将项目移植到Micronaut(v1.1.1),但发现Redis有问题。
我只是想在Redis中保存一个简单的POJO,但是当我尝试“保存”它时会出现以下错误:
io.lettuce.core.RedisException: io.netty.handler.codec.EncoderException: Cannot encode command. Please close the connection as the connection state may be out of sync.
代码非常简单(HERE,您可以找到完整的测试。):
class DummyTest {
@Test
public void testIssue() throws Exception {
final Date now = Date.from(Instant.now());
CatalogContent expectedContentOne = CatalogContent.builder()
.contentId(1)
.status(ContentStatus.AVAILABLE)
.title("uno")
.streamId(1)
.available(now)
.tags(Set.of("tag1", "tag2"))
.build();
repository.save(expectedContentOne);
}
}
/.../
class CatalogContentRepository {
private StatefulRedisConnection<String, CatalogContent> connection;
public CatalogContentRepository(StatefulRedisConnection<String, CatalogContent> connection) {
this.connection = connection;
}
public void save(CatalogContent content) {
RedisCommands<String, CatalogContent> redisApi = connection.sync();
redisApi.set(String.valueOf(content.getContentId()),content); //Error here!
}
}
任何想法都会受到欢迎。
谢谢。
答案 0 :(得分:0)
记录下来,我将回答我自己的问题:
现在(20190514)Micronaut仅使用硬编码的UTF8字符串编解码器生成StatefulRedisConnection<String,String>
。
要更改此设置,您必须替换DefaultRedisClientFactory
并定义一个返回所需的StatefulRedisConnection
的方法,
使用您喜欢的编解码器。
就我而言:
@Requires(beans = DefaultRedisConfiguration.class)
@Singleton
@Factory
@Replaces(factory = DefaultRedisClientFactory.class)
public class RedisClientFactory extends AbstractRedisClientFactory {
@Bean(preDestroy = "shutdown")
@Singleton
@Primary
@Override
public RedisClient redisClient(@Primary AbstractRedisConfiguration config) {
return super.redisClient(config);
}
@Bean(preDestroy = "close")
@Singleton
@Primary
public StatefulRedisConnection<String, Object> myRedisConnection(@Primary RedisClient redisClient) {
return redisClient.connect(new SerializedObjectCodec());
}
@Bean(preDestroy = "close")
@Singleton
@Primary
@Override
public StatefulRedisConnection<String, String> redisConnection(@Primary RedisClient redisClient) {
throw new RuntimeException("puta mierda");
}
@Override
@Bean(preDestroy = "close")
@Singleton
public StatefulRedisPubSubConnection<String, String> redisPubSubConnection(@Primary RedisClient redisClient) {
return super.redisPubSubConnection(redisClient);
}
}
编解码器取自Redis Lettuce wiki
public class SerializedObjectCodec implements RedisCodec<String, Object> {
private Charset charset = Charset.forName("UTF-8");
@Override
public String decodeKey(ByteBuffer bytes) {
return charset.decode(bytes).toString();
}
@Override
public Object decodeValue(ByteBuffer bytes) {
try {
byte[] array = new byte[bytes.remaining()];
bytes.get(array);
ObjectInputStream is = new ObjectInputStream(new ByteArrayInputStream(array));
return is.readObject();
} catch (Exception e) {
return null;
}
}
@Override
public ByteBuffer encodeKey(String key) {
return charset.encode(key);
}
@Override
public ByteBuffer encodeValue(Object value) {
try {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bytes);
os.writeObject(value);
return ByteBuffer.wrap(bytes.toByteArray());
} catch (IOException e) {
return null;
}
}
}