5
5
import lombok .Getter ;
6
6
import lombok .extern .slf4j .Slf4j ;
7
7
import org .springframework .cache .support .AbstractValueAdaptingCache ;
8
+ import org .springframework .cache .support .NullValue ;
8
9
import 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 ;
10
12
import org .springframework .util .CollectionUtils ;
11
13
import org .springframework .util .StringUtils ;
12
14
@@ -44,6 +46,10 @@ public class RedisCaffeineCache extends AbstractValueAdaptingCache {
44
46
45
47
private final Map <String , ReentrantLock > keyLockMap = new ConcurrentHashMap <>();
46
48
49
+ private RedisSerializer <String > stringSerializer = RedisSerializer .string ();
50
+
51
+ private RedisSerializer <Object > javaSerializer = RedisSerializer .java ();
52
+
47
53
public RedisCaffeineCache (String name , RedisTemplate <Object , Object > stringKeyRedisTemplate ,
48
54
Cache <Object , Object > caffeineCache , CacheConfigProperties cacheConfigProperties ) {
49
55
super (cacheConfigProperties .isCacheNullValues ());
@@ -105,11 +111,10 @@ public void put(Object key, Object value) {
105
111
106
112
@ Override
107
113
public ValueWrapper putIfAbsent (Object key , Object value ) {
108
- Object cacheKey = getKey (key );
109
114
Object prevValue ;
110
115
// 考虑使用分布式锁,或者将redis的setIfAbsent改为原子性操作
111
116
synchronized (key ) {
112
- prevValue = stringKeyRedisTemplate . opsForValue (). get ( cacheKey );
117
+ prevValue = getRedisValue ( key );
113
118
if (prevValue == null ) {
114
119
doPut (key , value );
115
120
}
@@ -118,14 +123,9 @@ public ValueWrapper putIfAbsent(Object key, Object value) {
118
123
}
119
124
120
125
private void doPut (Object key , Object value ) {
121
- Duration expire = getExpire (value );
122
126
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 );
129
129
130
130
push (new CacheMessage (this .name , key ));
131
131
@@ -165,9 +165,7 @@ protected Object lookup(Object key) {
165
165
return value ;
166
166
}
167
167
168
- // 避免自动一个 RedisTemplate 覆盖失效
169
- stringKeyRedisTemplate .setKeySerializer (new StringRedisSerializer ());
170
- value = stringKeyRedisTemplate .opsForValue ().get (cacheKey );
168
+ value = getRedisValue (key );
171
169
172
170
if (value != null ) {
173
171
log .debug ("get cache from redis and put in caffeine, the key is : {}" , cacheKey );
@@ -186,7 +184,7 @@ private Duration getExpire(Object value) {
186
184
if (cacheNameExpire == null ) {
187
185
cacheNameExpire = defaultExpiration ;
188
186
}
189
- if (value == null && this .defaultNullValuesExpiration != null ) {
187
+ if (( value == null || value == NullValue . INSTANCE ) && this .defaultNullValuesExpiration != null ) {
190
188
cacheNameExpire = this .defaultNullValuesExpiration ;
191
189
}
192
190
return cacheNameExpire ;
@@ -200,7 +198,19 @@ private Duration getExpire(Object value) {
200
198
* @version 1.0.0
201
199
*/
202
200
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);
204
214
}
205
215
206
216
/**
@@ -220,4 +230,29 @@ public void clearLocal(Object key) {
220
230
}
221
231
}
222
232
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
+
223
258
}
0 commit comments