задний план
Изначально проект использовал jedis для подключения redis, но учитывая необходимость использования блокировки redis, его заменили на удобный и быстрыйredisson, но после использования redisson будет сообщено об ошибке декодирования Конкретная информация следующая:
2019-05-15 13:39:59.973 [redisson-netty-2-3] ERROR o.r.c.h.CommandDecoder [decodeCommand:203] - Unable to decode data. channel: [id: 0x477c5ced, L:/192.168.4.94:57423 - R:10.10.10.43/10.10.10.43:6379], reply: ReplayingDecoderByteBuf(ridx=102, widx=102), command: (GET), params: [Geek:xxxxx:xxxx]
java.io.IOException: java.lang.NullPointerException
at org.nustaq.serialization.FSTObjectInput.readObject(FSTObjectInput.java:247)
at org.redisson.codec.FstCodec$1.decode(FstCodec.java:228)
at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:368)
at org.redisson.client.handler.CommandDecoder.decodeCommand(CommandDecoder.java:200)
at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:140)
at org.redisson.client.handler.CommandDecoder.decode(CommandDecoder.java:115)
at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:502)
at io.netty.handler.codec.ReplayingDecoder.callDecode(ReplayingDecoder.java:366)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:278)
тестовый код
RBucket ste = redissonClient.getBucket("Geek:add:ddd");
Object re = ste.get();
Учитывая проблему, которая может быть вызвана сериализацией, выяснитеNullPointer 3.10.6, установите кодек наStringCodec
,Прямо сейчас
redissonClient.getConfig().setCodec(new StringCodec());
Но это не решило проблему, redisson по-прежнему использует дефолтныйFstCodec
, с помощью мощной функции подсказки вы можете видеть, что getBucket принимает параметр кодека
Измените код на
RBucket ste = redissonClient.getBucket("Geek:add:ddd", new StringCodec());
String re = ste.get();
Идеальное решение
вопрос
Почему прямая установка конфига redisson не действует?Пошагово проверяйте исходный кодRedissonObject#RedissonObject
public RedissonObject(CommandAsyncExecutor commandExecutor, String name) {
this(commandExecutor.getConnectionManager().getCodec(), commandExecutor, name);
}
Видно, что redisson по умолчанию отConnectionManager
получатьcodec
способ, продолжать видеть, чтобыSingleConnectionManager
Например,SingleConnectionManager
даMasterSlaveConnectionManager
Подкласс , конкретное отношение диаграммы классов
config.java
public Config(Config oldConf) {
setExecutor(oldConf.getExecutor());
if (oldConf.getCodec() == null) {
// use it by default
oldConf.setCodec(new FstCodec());
}
......
}
То есть, когда обнаруживается, что исходный кодек пуст, он устанавливается вFstCodec
Взгляните на ключевую часть кода конфигурации Redisson.java.
protected Redisson(Config config) {
this.config = config;
Config configCopy = new Config(config);
connectionManager = ConfigSupport.createConnectionManager(configCopy);
evictionScheduler = new EvictionScheduler(connectionManager.getCommandExecutor());
writeBehindService = new WriteBehindService(connectionManager.getCommandExecutor());
}
public static RedissonClient create(Config config) {
Redisson redisson = new Redisson(config);
if (config.isReferenceEnabled()) {
redisson.enableRedissonReferenceSupport();
}
return redisson;
}
Видно, что конфигурация передается при инициализации redisson.
потому что я используюredisson-spring-boot-starter
, взгляните на то, как инициализируется стартер Стартер redisson по умолчанию использует конфигурацию spring-data-redis.
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(RedissonClient.class)
public RedissonClient redisson() throws IOException {
Config config = null;
....
if (redissonProperties.getConfig() != null) {
....
} else {
config = new Config();
String prefix = "redis://";
Method method = ReflectionUtils.findMethod(RedisProperties.class, "isSsl");
if (method != null && (Boolean)ReflectionUtils.invokeMethod(method, redisProperties)) {
prefix = "rediss://";
}
config.useSingleServer()
.setAddress(prefix + redisProperties.getHost() + ":" + redisProperties.getPort())
.setConnectTimeout(timeout)
.setDatabase(redisProperties.getDatabase())
.setPassword(redisProperties.getPassword());
}
return Redisson.create(config);
Возвращаясь к вопросу в начале, почему установка кодека redisson не вступает в силу напрямую? Из приведенного выше анализа мы можем узнать, что кодек унифицированных настроек redisson в основном передается через инициализацию.ConnectionManagerзаставить кодек вступить в силу и передатьredissonClient.getConfig().setCodec(...)
путь не меняетсяConnectionManagerкодировка в .
В заключение:
- Если вы хотите настроить кодек, вам нужно самостоятельно инициализировать redissonClient [вызвать Redisson.create(config)] или переписать redisson-starter
- Когда степень настройки невелика, кодек по умолчанию можно использовать напрямую или в тело метода можно передать определенный кодек.
Reference
Эта статья написанаЗаблудший старый фермерсоздавать, использоватьCC BY 4.0 CNсоглашение к лицензии. Ее можно свободно воспроизводить и цитировать, но с обязательной подписью автора и указанием источника статьи.