55import lombok .Getter ;
66import lombok .extern .slf4j .Slf4j ;
77import org .springframework .cache .support .AbstractValueAdaptingCache ;
8+ import org .springframework .cache .support .NullValue ;
89import org .springframework .data .redis .core .RedisTemplate ;
9- import org .springframework .data .redis .serializer .StringRedisSerializer ;
10+ import org .springframework .data .redis .serializer .RedisSerializer ;
11+ import org .springframework .util .Assert ;
1012import org .springframework .util .CollectionUtils ;
1113import org .springframework .util .StringUtils ;
1214
@@ -44,6 +46,10 @@ public class RedisCaffeineCache extends AbstractValueAdaptingCache {
4446
4547 private final Map <String , ReentrantLock > keyLockMap = new ConcurrentHashMap <>();
4648
49+ private RedisSerializer <String > stringSerializer = RedisSerializer .string ();
50+
51+ private RedisSerializer <Object > javaSerializer = RedisSerializer .java ();
52+
4753 public RedisCaffeineCache (String name , RedisTemplate <Object , Object > stringKeyRedisTemplate ,
4854 Cache <Object , Object > caffeineCache , CacheConfigProperties cacheConfigProperties ) {
4955 super (cacheConfigProperties .isCacheNullValues ());
@@ -105,11 +111,10 @@ public void put(Object key, Object value) {
105111
106112 @ Override
107113 public ValueWrapper putIfAbsent (Object key , Object value ) {
108- Object cacheKey = getKey (key );
109114 Object prevValue ;
110115 // 考虑使用分布式锁,或者将redis的setIfAbsent改为原子性操作
111116 synchronized (key ) {
112- prevValue = stringKeyRedisTemplate . opsForValue (). get ( cacheKey );
117+ prevValue = getRedisValue ( key );
113118 if (prevValue == null ) {
114119 doPut (key , value );
115120 }
@@ -118,14 +123,9 @@ public ValueWrapper putIfAbsent(Object key, Object value) {
118123 }
119124
120125 private void doPut (Object key , Object value ) {
121- Duration expire = getExpire (value );
122126 value = toStoreValue (value );
123- if (!expire .isNegative () && !expire .isZero ()) {
124- stringKeyRedisTemplate .opsForValue ().set (getKey (key ), value , expire );
125- }
126- else {
127- stringKeyRedisTemplate .opsForValue ().set (getKey (key ), value );
128- }
127+ Duration expire = getExpire (value );
128+ setRedisValue (key , value , expire );
129129
130130 push (new CacheMessage (this .name , key ));
131131
@@ -165,9 +165,7 @@ protected Object lookup(Object key) {
165165 return value ;
166166 }
167167
168- // 避免自动一个 RedisTemplate 覆盖失效
169- stringKeyRedisTemplate .setKeySerializer (new StringRedisSerializer ());
170- value = stringKeyRedisTemplate .opsForValue ().get (cacheKey );
168+ value = getRedisValue (key );
171169
172170 if (value != null ) {
173171 log .debug ("get cache from redis and put in caffeine, the key is : {}" , cacheKey );
@@ -186,7 +184,7 @@ private Duration getExpire(Object value) {
186184 if (cacheNameExpire == null ) {
187185 cacheNameExpire = defaultExpiration ;
188186 }
189- if (value == null && this .defaultNullValuesExpiration != null ) {
187+ if (( value == null || value == NullValue . INSTANCE ) && this .defaultNullValuesExpiration != null ) {
190188 cacheNameExpire = this .defaultNullValuesExpiration ;
191189 }
192190 return cacheNameExpire ;
@@ -200,7 +198,19 @@ private Duration getExpire(Object value) {
200198 * @version 1.0.0
201199 */
202200 private void push (CacheMessage message ) {
203- stringKeyRedisTemplate .convertAndSend (topic , message );
201+
202+ /**
203+ * 为了能自定义redisTemplate,发布订阅的序列化方式固定为jdk序列化方式。
204+ */
205+ Assert .hasText (topic , "a non-empty channel is required" );
206+ byte [] rawChannel = stringSerializer .serialize (topic );
207+ byte [] rawMessage = javaSerializer .serialize (message );
208+ stringKeyRedisTemplate .execute ((connection ) -> {
209+ connection .publish (rawChannel , rawMessage );
210+ return null ;
211+ }, true );
212+
213+ // stringKeyRedisTemplate.convertAndSend(topic, message);
204214 }
205215
206216 /**
@@ -220,4 +230,29 @@ public void clearLocal(Object key) {
220230 }
221231 }
222232
233+ private void setRedisValue (Object key , Object value , Duration expire ) {
234+
235+ Object convertValue = value ;
236+ if (value == null || value == NullValue .INSTANCE ) {
237+ convertValue = RedisNullValue .REDISNULLVALUE ;
238+ }
239+
240+ if (!expire .isNegative () && !expire .isZero ()) {
241+ stringKeyRedisTemplate .opsForValue ().set (getKey (key ), convertValue , expire );
242+ }
243+ else {
244+ stringKeyRedisTemplate .opsForValue ().set (getKey (key ), convertValue );
245+ }
246+ }
247+
248+ private Object getRedisValue (Object key ) {
249+
250+ // NullValue在不同序列化方式中存在问题,因此自定义了RedisNullValue做个转化。
251+ Object value = stringKeyRedisTemplate .opsForValue ().get (getKey (key ));
252+ if (value != null && value instanceof RedisNullValue ) {
253+ value = NullValue .INSTANCE ;
254+ }
255+ return value ;
256+ }
257+
223258}
0 commit comments