background

The project originally used Jedis to connect redis, but considering the need to use Redis lock, it was replaced with a convenient and fast Redisson. However, decode error will be reported after using Redisson, and the specific information is as follows:

2019-05-15 13:39:59.973 [redisson-nety-2-3] ERROR o.r.c.h.CommandDecoder [decomand :203] - Unable to decode data Channel: [id: 0 x477c5ced, L: / 192.168.4.94:57423 - R: 10.10.10.43/10.10.10.43:6379], the 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)Copy the code

The test code

RBucket ste = redissonClient.getBucket("Geek:add:ddd");
Object re = ste.get();Copy the code

NullPointer 3.10.6, set codec to StringCodec, i.e

redissonClient.getConfig().setCodec(new StringCodec());Copy the code

However, redisson still uses the default FstCodec, and you can see from the powerful hints of IDEA that getBucket accepts a CODEC parameter

Modify the code to

RBucket ste = redissonClient.getBucket("Geek:add:ddd", new StringCodec());
String re = ste.get();Copy the code

The perfect solution

The problem

RedissonObject#RedissonObject RedissonObject

public RedissonObject(CommandAsyncExecutor commandExecutor, String name) {
        this(commandExecutor.getConnectionManager().getCodec(), commandExecutor, name);
}Copy the code

You can see that redisson gets the CODEC method from The ConnectionManager by default. Moving on, take SingleConnectionManager as an example. SingleConnectionManager is a subclass of MasterSlaveConnectionManager, the specific relations of class diagram

config.java

public Config(Config oldConf) { setExecutor(oldConf.getExecutor()); if (oldConf.getCodec() == null) { // use it by default oldConf.setCodec(new FstCodec()); }... }Copy the code

That is, if the original CODEC is detected to be empty, set it to FstCodec

Take a look at the redisson.java configuration key code

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;
}Copy the code

As you can see, config is passed in when Redisson initializes

Because I use the redisson-spring-boot-starter, take a look at how the starter is initialized. The redisson starter uses the spring-data-redis configuration by default.

@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);Copy the code

Going back to the original question, why doesn’t setting redisson Codec directly work? Redissonclient.getconfig ().setCodec(…) redissonClient.getConfig().setCodec(… Does not change the encoding in ConnectionManager.

Conclusion:

  1. If you want to customize the CODEC, you need to initialize redissonClient yourself [call redisson.create (config)] or override redisson-starter
  2. When the degree of customization is low, the default CODEC can be used directly, or a specific CODEC can be passed into the method body

Reference

This article is written BY misguided Lao Nong and licensed BY CC BY 4.0CN. It can be reproduced and quoted freely, but the author must be signed and indicate the source of the article.