一.简介 简单的说,RedisTemplate
和StringRedisTemplate
的关系如下:
1.StringRedisTemplate
是RedisTemplate
的子类。
2.StringRedisTemplate
的各个序列化策略都是StringRedisSerializer
,而RedisTemplate
用的是JdkSerializationRedisSerializer
。
二.RedisTemplate和StringRedisTemplate的代码结构 从RedisTemplate
类说起。
在RedisTemplate
类中,定义了这样四个变量:
1 2 3 4 5 6 7 8 @Nullable private RedisSerializer keySerializer = null ;@Nullable private RedisSerializer valueSerializer = null ;@Nullable private RedisSerializer hashKeySerializer = null ;@Nullable private RedisSerializer hashValueSerializer = null ;
分别代表了普通key
,value
,和Hash
类型的key
,value的序列化策略,可以分别设置。
另外定义变量,用来指定默认的序列化策略:
1 2 @Nullable private RedisSerializer<?> defaultSerializer;
在RedisTemplate
类中,定义了afterPropertiesSet()
方法,当Spring
创建RedisTemplate
类的对象时,会调用这个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public void afterPropertiesSet () { super .afterPropertiesSet(); boolean defaultUsed = false ; if (this .defaultSerializer == null ) { this .defaultSerializer = new JdkSerializationRedisSerializer (this .classLoader != null ? this .classLoader : this .getClass().getClassLoader()); } if (this .enableDefaultSerializer) { if (this .keySerializer == null ) { this .keySerializer = this .defaultSerializer; defaultUsed = true ; } if (this .valueSerializer == null ) { this .valueSerializer = this .defaultSerializer; defaultUsed = true ; } if (this .hashKeySerializer == null ) { this .hashKeySerializer = this .defaultSerializer; defaultUsed = true ; } if (this .hashValueSerializer == null ) { this .hashValueSerializer = this .defaultSerializer; defaultUsed = true ; } } if (this .enableDefaultSerializer && defaultUsed) { Assert.notNull(this .defaultSerializer, "default serializer null and not all serializers initialized" ); } if (this .scriptExecutor == null ) { this .scriptExecutor = new DefaultScriptExecutor (this ); } this .initialized = true ; }
可以看到,在默认情况下,RedisTemplate
使用的默认序列化策略是JdkSerializationRedisSerializer
。包括RedisTemplate
下的key
,value
,hash-key
,hash-value的序列化,都用这种策略。
再来看看StringRedisTemplate
,他作为RedisTemplate的子类,只是修改了序列化策略:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class StringRedisTemplate extends RedisTemplate <String, String> { public StringRedisTemplate () { RedisSerializer<String> stringSerializer = new StringRedisSerializer (); this .setKeySerializer(stringSerializer); this .setValueSerializer(stringSerializer); this .setHashKeySerializer(stringSerializer); this .setHashValueSerializer(stringSerializer); } public StringRedisTemplate (RedisConnectionFactory connectionFactory) { this (); this .setConnectionFactory(connectionFactory); this .afterPropertiesSet(); } protected RedisConnection preProcessConnection (RedisConnection connection, boolean existingConnection) { return new DefaultStringRedisConnection (connection); } }
以上就是StringRedisTemplate
整个类的内容,可以看到,在他的默认构造中,key
,value
,hash-key
,hash-value
都使用的是StringRedisSerializer类作为序列化策略。这也就是StringRedisTemplate
和他的父类RedisTemplate的主要区别。
三.序列化策略 更进一步,看一下这个序列化策略是什么。
上面提到的StringRedisSerializer
和JdkSerializationRedisSerializer
都是序列化策略类,他们都实现了一个RedisSerializer<T>
接口:
1 2 3 4 5 6 7 public interface RedisSerializer <T> { @Nullable byte [] serialize(@Nullable T var1) throws SerializationException; @Nullable T deserialize (@Nullable byte [] var1) throws SerializationException; }
接口表达的意思很简单,两个方法,serialize用于序列化,把对象变为byte
数组,deserialize
用于反序列化,把byte数组转为对象。
StringRedisSerializer 看看StringRedisSerializer
是怎么做的:
1.StringRedisSerializer的构造:
1 2 3 4 5 6 7 8 public StringRedisSerializer () { this (StandardCharsets.UTF_8); } public StringRedisSerializer (Charset charset) { Assert.notNull(charset, "Charset must not be null!" ); this .charset = charset; }
定义了编码格式,默认UTF_8
。
2.StringRedisSerializer的serialize和deserialize方法:
1 2 3 4 5 6 7 public String deserialize (@Nullable byte [] bytes) { return bytes == null ? null : new String (bytes, this .charset); } public byte [] serialize(@Nullable String string) { return string == null ? null : string.getBytes(this .charset); }
可以看到,StringRedisSerializer
采用的是字符串和对应编码下二进制数组之间的转换。
在这种编码格式下,如果我们向redis保存信息,然后用客户端访问Redis
时,只要编码格式一致,就能看到保存信息的原文。保存字符串ABC
,客户端看到的也是字符串ABC
。
JdkSerializationRedisSerializer 然后对比看看JdkSerializationRedisSerializer
是怎么做的。
1.JdkSerializationRedisSerializer的构造:
1 2 3 4 5 6 7 8 9 10 private final Converter<Object, byte []> serializer;private final Converter<byte [], Object> deserializer;public JdkSerializationRedisSerializer () { this (new SerializingConverter (), new DeserializingConverter ()); } public JdkSerializationRedisSerializer (ClassLoader classLoader) { this (new SerializingConverter (), new DeserializingConverter (classLoader)); }
可以看到,JdkSerializationRedisSerializer
定义了两个变量,serializer和deserializer
,显然是用来序列化和反序列化的,他们两个的类型是一样的,都是Converter接口,只是泛型不同。
Converter接口:
1 2 3 4 5 @FunctionalInterface public interface Converter <S, T> { @Nullable T convert (S source) ; }
就一个方法。
另外在JdkSerializationRedisSerializer
的构造中,对serializer和deserializer
进行了初始化,使用SerializingConverter
和DeserializingConverter作为实现类。
2.JdkSerializationRedisSerializer的serialize和deserialize方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public Object deserialize (@Nullable byte [] bytes) { if (SerializationUtils.isEmpty(bytes)) { return null ; } else { try { return this .deserializer.convert(bytes); } catch (Exception var3) { throw new SerializationException ("Cannot deserialize" , var3); } } } public byte [] serialize(@Nullable Object object) { if (object == null ) { return SerializationUtils.EMPTY_ARRAY; } else { try { return (byte [])this .serializer.convert(object); } catch (Exception var3) { throw new SerializationException ("Cannot serialize" , var3); } } }
其实就是调用了对应Converter
的convert
方法。
3.关于Converter
既然到这了,就再深入一步,看看SerializingConverter
和DeserializingConverter的convert
方法。
首先,序列化:
SerializingConverter
的相关方法,贴一部分关键的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public SerializingConverter () { this .serializer = new DefaultSerializer (); } @Override public byte [] convert(Object source) { ByteArrayOutputStream byteStream = new ByteArrayOutputStream (1024 ); try { this .serializer.serialize(source, byteStream); return byteStream.toByteArray(); } catch (Throwable ex) { throw new SerializationFailedException ("Failed to serialize object using " + this .serializer.getClass().getSimpleName(), ex); } }
可以看到,SerializingConverter
类定义了serializer
变量,用DefaultSerializer 类实现,序列化的方式是调用DefaultSerializer
的serialize
方法:
1 2 3 4 5 6 7 8 9 10 @Override public void serialize (Object object, OutputStream outputStream) throws IOException { if (!(object instanceof Serializable)) { throw new IllegalArgumentException (getClass().getSimpleName() + " requires a Serializable payload " + "but received an object of type [" + object.getClass().getName() + "]" ); } ObjectOutputStream objectOutputStream = new ObjectOutputStream (outputStream); objectOutputStream.writeObject(object); objectOutputStream.flush(); }
DefaultSerializer
的serialize
方法使用了ObjectOutputStream
,调用writeObject方法序列化对象。
对应的,反序列化:
DeserializingConverter
的convert方法,贴一下相关代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public DeserializingConverter () { this .deserializer = new DefaultDeserializer (); } @Override public Object convert (byte [] source) { ByteArrayInputStream byteStream = new ByteArrayInputStream (source); try { return this .deserializer.deserialize(byteStream); } catch (Throwable ex) { throw new SerializationFailedException ("Failed to deserialize payload. " + "Is the byte array a result of corresponding serialization for " + this .deserializer.getClass().getSimpleName() + "?" , ex); } }
可见DeserializingConverter
使用了DefaultDeserializer 作为反序列化工具,调用了他的deserialize方法:
1 2 3 4 5 6 7 8 9 10 11 @Override @SuppressWarnings("resource") public Object deserialize (InputStream inputStream) throws IOException { ObjectInputStream objectInputStream = new ConfigurableObjectInputStream (inputStream, this .classLoader); try { return objectInputStream.readObject(); } catch (ClassNotFoundException ex) { throw new NestedIOException ("Failed to deserialize object type" , ex); } }
对比SerializingConverter
,DeserializingConverter
使用的是ConfigurableObjectInputStream
,并调用他的readObject
方法进行反序列化。
这种序列化方式,如果保存信息至redis
,用客户端查看时,保存的信息看起来像是在原来的字符前面加了几个字符。
比如:
1 2 3 4 JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer ();StringRedisSerializer stringSerializer = new StringRedisSerializer ();byte [] jdkByteArr = jdkSerializer.serialize("CSDN博客" );byte [] stringByteArr = stringSerializer.serialize("CSDN博客" );
这种情况下,得到的byte
数组是:
jdkByteArr
:
{-84,-19,0,5,116,0,10,67,83,68,78,-27,-115,-102,-27,-82,-94}
stringByteArr:
{67,83,68,78,-27,-115,-102,-27,-82,-94}
StringRedisSerializer
把字符串本身转化成byte
数组,而JdkSerializationRedisSerializer
在数组前面加了几个字符,这些字符也会被保存到redis中。
所以,从数据上来说,这两种序列化策略处理的数据是不会共通的,各人管各人的。
四.关于redisTemplate的Operations 使用redisTemplate
时,除了调用execute
方法并自定义RedisCallback之外,还可以使用redisTemplate
提供的几个Operations接口。
redisTemplate
中定义了以下几个Operations
:
1 2 3 4 5 6 7 8 9 10 11 12 @Nullable private ValueOperations<K, V> valueOps;@Nullable private ListOperations<K, V> listOps;@Nullable private SetOperations<K, V> setOps;@Nullable private ZSetOperations<K, V> zSetOps;@Nullable private GeoOperations<K, V> geoOps;@Nullable private HyperLogLogOperations<K, V> hllOps;
这几个Operations
接口,分别提供了对不同种类数据的操作方法。
以ValueOperations
为例,他提供的方法有:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 void set (K var1, V var2) ;void set (K var1, V var2, long var3, TimeUnit var5) ;@Nullable Boolean setIfAbsent (K var1, V var2) ; void multiSet (Map<? extends K, ? extends V> var1) ;@Nullable Boolean multiSetIfAbsent (Map<? extends K, ? extends V> var1) ; @Nullable V get (Object var1) ; @Nullable V getAndSet (K var1, V var2) ; @Nullable List<V> multiGet (Collection<K> var1) ; @Nullable Long increment (K var1, long var2) ; @Nullable Double increment (K var1, double var2) ; @Nullable Integer append (K var1, String var2) ; @Nullable String get (K var1, long var2, long var4) ; void set (K var1, V var2, long var3) ;@Nullable Long size (K var1) ; @Nullable Boolean setBit (K var1, long var2, boolean var4) ; @Nullable Boolean getBit (K var1, long var2) ;
其他的Operations
提供的方法各有不同,但是这些Operations
的使用方式都是相同的。
不同的Operations分别通过RedisTemplate
的以下方法获取:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public ValueOperations<K, V> opsForValue () { if (this .valueOps == null ) { this .valueOps = new DefaultValueOperations (this ); } return this .valueOps; } public ListOperations<K, V> opsForList () { if (this .listOps == null ) { this .listOps = new DefaultListOperations (this ); } return this .listOps; } public SetOperations<K, V> opsForSet () { if (this .setOps == null ) { this .setOps = new DefaultSetOperations (this ); } return this .setOps; } public ZSetOperations<K, V> opsForZSet () { if (this .zSetOps == null ) { this .zSetOps = new DefaultZSetOperations (this ); } return this .zSetOps; } public GeoOperations<K, V> opsForGeo () { if (this .geoOps == null ) { this .geoOps = new DefaultGeoOperations (this ); } return this .geoOps; }
可见,在这些获得Operations
的方法中,都提供了一个默认实现类,并且把RedisTemplate
对象本身当做参数传给了这个实现类。
还是以ValueOperations
为例,RedisTemplate
提供的默认实现类是DefaultValueOperations,看看这个类的源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 package org.springframework.data.redis.core;import java.util.Collection;import java.util.Collections;import java.util.Iterator;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import java.util.concurrent.TimeUnit;import org.springframework.dao.DataAccessException;import org.springframework.data.redis.connection.RedisConnection;import org.springframework.data.redis.core.AbstractOperations.ValueDeserializingRedisCallback;class DefaultValueOperations <K, V> extends AbstractOperations <K, V> implements ValueOperations <K, V> { DefaultValueOperations(RedisTemplate<K, V> template) { super (template); } public V get (Object key) { return this .execute(new AbstractOperations <K, V>.ValueDeserializingRedisCallback(key) { protected byte [] inRedis(byte [] rawKey, RedisConnection connection) { return connection.get(rawKey); } }, true ); } public V getAndSet (K key, V newValue) { final byte [] rawValue = this .rawValue(newValue); return this .execute(new AbstractOperations <K, V>.ValueDeserializingRedisCallback(key) { protected byte [] inRedis(byte [] rawKey, RedisConnection connection) { return connection.getSet(rawKey, rawValue); } }, true ); } public Long increment (K key, long delta) { byte [] rawKey = this .rawKey(key); return (Long)this .execute((connection) -> { return connection.incrBy(rawKey, delta); }, true ); } public Double increment (K key, double delta) { byte [] rawKey = this .rawKey(key); return (Double)this .execute((connection) -> { return connection.incrBy(rawKey, delta); }, true ); } public Integer append (K key, String value) { byte [] rawKey = this .rawKey(key); byte [] rawString = this .rawString(value); return (Integer)this .execute((connection) -> { Long result = connection.append(rawKey, rawString); return result != null ? result.intValue() : null ; }, true ); } public String get (K key, long start, long end) { byte [] rawKey = this .rawKey(key); byte [] rawReturn = (byte [])this .execute((connection) -> { return connection.getRange(rawKey, start, end); }, true ); return this .deserializeString(rawReturn); } public List<V> multiGet (Collection<K> keys) { if (keys.isEmpty()) { return Collections.emptyList(); } else { byte [][] rawKeys = new byte [keys.size()][]; int counter = 0 ; Object hashKey; for (Iterator var4 = keys.iterator(); var4.hasNext(); rawKeys[counter++] = this .rawKey(hashKey)) { hashKey = var4.next(); } List<byte []> rawValues = (List)this .execute((connection) -> { return connection.mGet(rawKeys); }, true ); return this .deserializeValues(rawValues); } } public void multiSet (Map<? extends K, ? extends V> m) { if (!m.isEmpty()) { Map<byte [], byte []> rawKeys = new LinkedHashMap (m.size()); Iterator var3 = m.entrySet().iterator(); while (var3.hasNext()) { Entry<? extends K , ? extends V > entry = (Entry)var3.next(); rawKeys.put(this .rawKey(entry.getKey()), this .rawValue(entry.getValue())); } this .execute((connection) -> { connection.mSet(rawKeys); return null ; }, true ); } } public Boolean multiSetIfAbsent (Map<? extends K, ? extends V> m) { if (m.isEmpty()) { return true ; } else { Map<byte [], byte []> rawKeys = new LinkedHashMap (m.size()); Iterator var3 = m.entrySet().iterator(); while (var3.hasNext()) { Entry<? extends K , ? extends V > entry = (Entry)var3.next(); rawKeys.put(this .rawKey(entry.getKey()), this .rawValue(entry.getValue())); } return (Boolean)this .execute((connection) -> { return connection.mSetNX(rawKeys); }, true ); } } public void set (K key, V value) { final byte [] rawValue = this .rawValue(value); this .execute(new AbstractOperations <K, V>.ValueDeserializingRedisCallback(key) { protected byte [] inRedis(byte [] rawKey, RedisConnection connection) { connection.set(rawKey, rawValue); return null ; } }, true ); } public void set (K key, V value, final long timeout, final TimeUnit unit) { final byte [] rawKey = this .rawKey(key); final byte [] rawValue = this .rawValue(value); this .execute(new RedisCallback <Object>() { public Object doInRedis (RedisConnection connection) throws DataAccessException { this .potentiallyUsePsetEx(connection); return null ; } public void potentiallyUsePsetEx (RedisConnection connection) { if (!TimeUnit.MILLISECONDS.equals(unit) || !this .failsafeInvokePsetEx(connection)) { connection.setEx(rawKey, TimeoutUtils.toSeconds(timeout, unit), rawValue); } } private boolean failsafeInvokePsetEx (RedisConnection connection) { boolean failed = false ; try { connection.pSetEx(rawKey, timeout, rawValue); } catch (UnsupportedOperationException var4) { failed = true ; } return !failed; } }, true ); } public Boolean setIfAbsent (K key, V value) { byte [] rawKey = this .rawKey(key); byte [] rawValue = this .rawValue(value); return (Boolean)this .execute((connection) -> { return connection.setNX(rawKey, rawValue); }, true ); } public void set (K key, V value, long offset) { byte [] rawKey = this .rawKey(key); byte [] rawValue = this .rawValue(value); this .execute((connection) -> { connection.setRange(rawKey, rawValue, offset); return null ; }, true ); } public Long size (K key) { byte [] rawKey = this .rawKey(key); return (Long)this .execute((connection) -> { return connection.strLen(rawKey); }, true ); } public Boolean setBit (K key, long offset, boolean value) { byte [] rawKey = this .rawKey(key); return (Boolean)this .execute((connection) -> { return connection.setBit(rawKey, offset, value); }, true ); } public Boolean getBit (K key, long offset) { byte [] rawKey = this .rawKey(key); return (Boolean)this .execute((connection) -> { return connection.getBit(rawKey, offset); }, true ); } }
所有Operations
实现类都是AbstractOperations
的子类,另外各自实现各自的接口。
实现类的方法中多数都是调用了this.execute()
方法,这个方法在父类AbstractOperations中,最终调用的其实也是RedisTemplate
的execute()
方法。
以上面DefaultValueOperations
的set()
方法为例,看一下代码:
1 2 3 4 5 6 7 8 9 public void set (K key, V value) { final byte [] rawValue = this .rawValue(value); this .execute(new AbstractOperations <K, V>.ValueDeserializingRedisCallback(key) { protected byte [] inRedis(byte [] rawKey, RedisConnection connection) { connection.set(rawKey, rawValue); return null ; } }, true ); }
首先是对value
的处理,调用this.rawValue()
方法,把value序列化成byte
数组,这个方法在父类AbstractOperations
中:
1 2 3 byte [] rawValue(Object value) { return this .valueSerializer() == null && value instanceof byte [] ? (byte [])((byte [])value) : this .valueSerializer().serialize(value); }
可见,代码用的是自己的valueSerializer
来序列化value
,这个valueSerializer来自RedisTemplate
。
回到set()
方法,value
序列化完成后,调用this.execute()
方法,给此方法传递的第一个参数是:
1 2 3 4 5 6 new AbstractOperations <K, V>.ValueDeserializingRedisCallback(key) { protected byte [] inRedis(byte [] rawKey, RedisConnection connection) { connection.set(rawKey, rawValue); return null ; } }
这个参数实际上是一个ValueDeserializingRedisCallback
对象,在其中定义了inRedis()
方法的实现。
this.execute()
方法在父类AbstractOperations中:
1 2 3 4 @Nullable <T> T execute (RedisCallback<T> callback, boolean b) { return this .template.execute(callback, b); }
其中this.template
指的就是初始化时传入的RedisTemplate
,其execute()方法是这样的:
1 2 3 4 @Nullable public <T> T execute (RedisCallback<T> action, boolean exposeConnection) { return this .execute(action, exposeConnection, false ); }
然后调用下面的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 @Nullable public <T> T execute (RedisCallback<T> action, boolean exposeConnection, boolean pipeline) { Assert.isTrue(this .initialized, "template not initialized; call afterPropertiesSet() before using it" ); Assert.notNull(action, "Callback object must not be null" ); RedisConnectionFactory factory = this .getRequiredConnectionFactory(); RedisConnection conn = null ; Object var11; try { if (this .enableTransactionSupport) { conn = RedisConnectionUtils.bindConnection(factory, this .enableTransactionSupport); } else { conn = RedisConnectionUtils.getConnection(factory); } boolean existingConnection = TransactionSynchronizationManager.hasResource(factory); RedisConnection connToUse = this .preProcessConnection(conn, existingConnection); boolean pipelineStatus = connToUse.isPipelined(); if (pipeline && !pipelineStatus) { connToUse.openPipeline(); } RedisConnection connToExpose = exposeConnection ? connToUse : this .createRedisConnectionProxy(connToUse); T result = action.doInRedis(connToExpose); if (pipeline && !pipelineStatus) { connToUse.closePipeline(); } var11 = this .postProcessResult(result, connToUse, existingConnection); } finally { RedisConnectionUtils.releaseConnection(conn, factory); } return var11; }
方法初始化了RedisConnection
,最后面调用了RedisCallback
的doInRedis()
方法,也就是这一行:
1 T result = action.doInRedis(connToExpose);
这里的变量action
就是在set()
方法中自定义的new AbstractOperations<K, V>.ValueDeserializingRedisCallback(key)
。
ValueDeserializingRedisCallback
类是AbstractOperations
的内部抽象类,他的doInRedis()
方法是这样的:
1 2 3 4 public final V doInRedis (RedisConnection connection) { byte [] result = this .inRedis(AbstractOperations.this .rawKey(this .key), connection); return AbstractOperations.this .deserializeValue(result); }
可见调用了inRedis()
方法,其第一个参数是序列化后的key
,调用的是AbstractOperations
的rawKey()
方法,代码如下:
1 2 3 4 byte [] rawKey(Object key) { Assert.notNull(key, "non null key required" ); return this .keySerializer() == null && key instanceof byte [] ? (byte [])((byte [])key) : this .keySerializer().serialize(key); }
这里把key
进行序列化,keySerializer()
方法从RedisTemplate
中获取keySerializer
,并由keySerializer
对key
进行序列化。
在ValueDeserializingRedisCallback
类中的inRedis()
方法是抽象方法,具体的实现在DefaultValueOperations
的set()
方法中,也就是这一部分:
1 2 3 4 protected byte [] inRedis(byte [] rawKey, RedisConnection connection) { connection.set(rawKey, rawValue); return null ; }
最终调用的是RedisConnection
的set()
方法,完成Redis
的set
操作。
以上就是在RedisTemplate中使用ValueOperations
进行set
操作的全部代码流程。
对Redis
的不同操作分散在RedisTemplate
的不同Operations中,只是调用的方法不同,调用流程都差不多。
参考地址