Skip to content

Commit 5e15beb

Browse files
committed
优化redis缓存 使用json方式。增加简单的监控
1 parent 27c9d6e commit 5e15beb

File tree

4 files changed

+258
-9
lines changed

4 files changed

+258
-9
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,24 @@
11
package org.hsweb.concureent.cache;
22

3+
import org.hsweb.concureent.cache.monitor.RedisMonitorCache;
4+
import org.hsweb.concureent.cache.redis.FastJsonRedisTemplate;
35
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
6+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
47
import org.springframework.cache.CacheManager;
58
import org.springframework.cache.annotation.CachingConfigurerSupport;
69
import org.springframework.cache.annotation.EnableCaching;
710
import org.springframework.cache.interceptor.KeyGenerator;
811
import org.springframework.context.annotation.Bean;
912
import org.springframework.context.annotation.Configuration;
13+
import org.springframework.data.redis.cache.DefaultRedisCachePrefix;
14+
import org.springframework.data.redis.cache.RedisCache;
1015
import org.springframework.data.redis.cache.RedisCacheManager;
1116
import org.springframework.data.redis.connection.RedisConnectionFactory;
1217
import org.springframework.data.redis.connection.jedis.JedisConnection;
1318
import org.springframework.data.redis.core.RedisOperations;
1419
import org.springframework.data.redis.core.RedisTemplate;
1520
import org.springframework.data.redis.core.StringRedisTemplate;
21+
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
1622
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
1723
import redis.clients.jedis.Jedis;
1824

@@ -26,8 +32,22 @@
2632
public class RedisCacheManagerAutoConfig extends CachingConfigurerSupport {
2733

2834
@Bean
29-
public CacheManager cacheManager(RedisTemplate redisTemplate) {
30-
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
35+
@ConditionalOnMissingBean(FastJsonRedisTemplate.class)
36+
public FastJsonRedisTemplate redisTemplate(
37+
RedisConnectionFactory redisConnectionFactory) {
38+
FastJsonRedisTemplate template = new FastJsonRedisTemplate(redisConnectionFactory);
39+
return template;
40+
}
41+
42+
@Bean
43+
public CacheManager cacheManager(FastJsonRedisTemplate redisTemplate) {
44+
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate){
45+
@Override
46+
protected RedisCache createCache(String cacheName) {
47+
long expiration = computeExpiration(cacheName);
48+
return new RedisMonitorCache(cacheName, new DefaultRedisCachePrefix().prefix(cacheName), redisTemplate, expiration);
49+
}
50+
};
3151
redisCacheManager.setUsePrefix(true);
3252
return redisCacheManager;
3353
}
@@ -37,11 +57,5 @@ public KeyGenerator wiselyKeyGenerator() {
3757
return new SimpleKeyGenerator();
3858
}
3959

40-
@Bean
41-
public RedisTemplate<String, String> redisTemplate(
42-
RedisConnectionFactory redisConnectionFactory) {
43-
StringRedisTemplate template = new StringRedisTemplate(redisConnectionFactory);
44-
template.setValueSerializer(new JdkSerializationRedisSerializer());
45-
return template;
46-
}
60+
4761
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
/*
2+
* Copyright 2011-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.hsweb.concureent.cache.monitor;
18+
19+
import static org.springframework.util.Assert.*;
20+
import static org.springframework.util.ObjectUtils.*;
21+
22+
import java.lang.reflect.Constructor;
23+
import java.util.Arrays;
24+
import java.util.Set;
25+
import java.util.concurrent.Callable;
26+
import java.util.stream.Collectors;
27+
28+
import org.hsweb.commons.StringUtils;
29+
import org.hsweb.web.core.cache.monitor.MonitorCache;
30+
import org.hsweb.web.core.utils.ThreadLocalUtils;
31+
import org.springframework.cache.Cache;
32+
import org.springframework.cache.support.SimpleValueWrapper;
33+
import org.springframework.dao.DataAccessException;
34+
import org.springframework.data.redis.RedisSystemException;
35+
import org.springframework.data.redis.cache.RedisCache;
36+
import org.springframework.data.redis.cache.RedisCacheElement;
37+
import org.springframework.data.redis.cache.RedisCacheKey;
38+
import org.springframework.data.redis.connection.RedisConnection;
39+
import org.springframework.data.redis.connection.ReturnType;
40+
import org.springframework.data.redis.core.RedisCallback;
41+
import org.springframework.data.redis.core.RedisOperations;
42+
import org.springframework.data.redis.serializer.RedisSerializer;
43+
import org.springframework.data.redis.serializer.StringRedisSerializer;
44+
import org.springframework.util.ClassUtils;
45+
46+
/**
47+
* Cache implementation on top of Redis.
48+
*
49+
* @author Costin Leau
50+
* @author Christoph Strobl
51+
* @author Thomas Darimont
52+
*/
53+
@SuppressWarnings("unchecked")
54+
public class RedisMonitorCache extends RedisCache implements Cache, MonitorCache {
55+
56+
@SuppressWarnings("rawtypes")//
57+
private final RedisOperations redisOperations;
58+
private final byte[] totalTimeKey;
59+
private final byte[] hitTimeKey;
60+
private final byte[] putTimeKey;
61+
private final byte[] keySetKey;
62+
private long expiration = 0;
63+
64+
public RedisMonitorCache(String name, byte[] prefix, RedisOperations<? extends Object, ? extends Object> redisOperations,
65+
long expiration) {
66+
super(name, prefix, redisOperations, expiration);
67+
this.expiration = expiration;
68+
this.redisOperations = redisOperations;
69+
this.keySetKey = (name + "~keys").getBytes();
70+
this.totalTimeKey = name.concat(":total-times").getBytes();
71+
this.hitTimeKey = name.concat(":hit-times").getBytes();
72+
this.putTimeKey = name.concat(":put-times").getBytes();
73+
}
74+
75+
@Override
76+
public <T> T get(Object key, Class<T> type) {
77+
String localCacheKey = "cache-".concat(String.valueOf(key));
78+
T localCache = ThreadLocalUtils.get(localCacheKey);
79+
if (localCache != null) {
80+
return localCache;
81+
}
82+
T v = super.get(key, type);
83+
redisOperations.execute((RedisCallback) connection -> {
84+
connection.incr(totalTimeKey);
85+
if (v != null) {
86+
connection.incr(hitTimeKey);
87+
}
88+
return null;
89+
});
90+
if (v != null) {
91+
ThreadLocalUtils.put(localCacheKey, v);
92+
}
93+
return v;
94+
}
95+
96+
@Override
97+
public ValueWrapper get(Object key) {
98+
String localCacheKey = "cache-".concat(String.valueOf(key));
99+
ValueWrapper localCache = ThreadLocalUtils.get(localCacheKey);
100+
if (localCache != null) {
101+
return localCache;
102+
}
103+
ValueWrapper wrapper = super.get(key);
104+
redisOperations.execute((RedisCallback) connection -> {
105+
connection.incr(totalTimeKey);
106+
if (wrapper != null) {
107+
connection.incr(hitTimeKey);
108+
}
109+
return null;
110+
});
111+
if (wrapper != null) {
112+
ThreadLocalUtils.put(localCacheKey, wrapper);
113+
}
114+
return wrapper;
115+
}
116+
117+
@Override
118+
public void put(Object key, Object value) {
119+
super.put(key, value);
120+
redisOperations.execute((RedisCallback) connection -> {
121+
connection.multi();
122+
connection.incr(putTimeKey);
123+
connection.sAdd(keySetKey, ((String) key).getBytes());
124+
if (expiration != 0) connection.expire(keySetKey, expiration);
125+
connection.exec();
126+
return null;
127+
});
128+
}
129+
130+
@Override
131+
public void evict(Object key) {
132+
super.evict(key);
133+
redisOperations.execute((RedisCallback) connection -> {
134+
connection.sRem(keySetKey, ((String) key).getBytes());
135+
return null;
136+
});
137+
}
138+
139+
@Override
140+
public void clear() {
141+
super.clear();
142+
redisOperations.delete(keySetKey);
143+
}
144+
145+
@Override
146+
public Set<Object> keySet() {
147+
return (Set<Object>) redisOperations.execute((RedisCallback) connection -> connection.sMembers(keySetKey).stream().map(String::new).collect(Collectors.toSet()));
148+
}
149+
150+
@Override
151+
public int size() {
152+
return redisOperations.opsForSet().size(new String(keySetKey)).intValue();
153+
}
154+
155+
@Override
156+
public long getTotalTimes() {
157+
return StringUtils.toInt(redisOperations.opsForValue().get(new String(totalTimeKey)));
158+
}
159+
160+
@Override
161+
public long getHitTimes() {
162+
return StringUtils.toInt(redisOperations.opsForValue().get(new String(hitTimeKey)));
163+
}
164+
165+
@Override
166+
public long getPutTimes() {
167+
return StringUtils.toInt(redisOperations.opsForValue().get(new String(putTimeKey)));
168+
}
169+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package org.hsweb.concureent.cache.redis;
2+
3+
import com.alibaba.fastjson.JSON;
4+
import com.alibaba.fastjson.serializer.SerializerFeature;
5+
import org.springframework.data.redis.serializer.RedisSerializer;
6+
import org.springframework.data.redis.serializer.SerializationException;
7+
8+
/**
9+
* @author zhouhao
10+
* @TODO
11+
*/
12+
public class FastJsonRedisSerializer implements RedisSerializer<Object> {
13+
@Override
14+
public byte[] serialize(Object o) throws SerializationException {
15+
if (o == null) return null;
16+
return JSON.toJSONBytes(o, SerializerFeature.WriteClassName);
17+
}
18+
19+
@Override
20+
public Object deserialize(byte[] bytes) throws SerializationException {
21+
if (bytes == null) return null;
22+
return JSON.parse(bytes);
23+
}
24+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package org.hsweb.concureent.cache.redis;
2+
3+
import org.springframework.data.redis.connection.DefaultStringRedisConnection;
4+
import org.springframework.data.redis.connection.RedisConnection;
5+
import org.springframework.data.redis.connection.RedisConnectionFactory;
6+
import org.springframework.data.redis.core.RedisTemplate;
7+
import org.springframework.data.redis.serializer.RedisSerializer;
8+
import org.springframework.data.redis.serializer.StringRedisSerializer;
9+
10+
/**
11+
* @author zhouhao
12+
* @TODO
13+
*/
14+
public class FastJsonRedisTemplate extends RedisTemplate<String, Object> {
15+
/**
16+
* Constructs a new <code>StringRedisTemplate</code> instance. {@link #setConnectionFactory(RedisConnectionFactory)}
17+
* and {@link #afterPropertiesSet()} still need to be called.
18+
*/
19+
public FastJsonRedisTemplate() {
20+
RedisSerializer<String> stringSerializer = new StringRedisSerializer();
21+
FastJsonRedisSerializer redisSerializer = new FastJsonRedisSerializer();
22+
setKeySerializer(stringSerializer);
23+
setValueSerializer(redisSerializer);
24+
setHashKeySerializer(stringSerializer);
25+
setHashValueSerializer(redisSerializer);
26+
}
27+
28+
/**
29+
* Constructs a new <code>StringRedisTemplate</code> instance ready to be used.
30+
*
31+
* @param connectionFactory connection factory for creating new connections
32+
*/
33+
public FastJsonRedisTemplate(RedisConnectionFactory connectionFactory) {
34+
this();
35+
setConnectionFactory(connectionFactory);
36+
afterPropertiesSet();
37+
}
38+
39+
protected RedisConnection preProcessConnection(RedisConnection connection, boolean existingConnection) {
40+
return new DefaultStringRedisConnection(connection);
41+
}
42+
}

0 commit comments

Comments
 (0)