Skip to content

Commit 965a1e0

Browse files
committed
添加redis序列化方式:Protostuff和Kryo两种方式
1 parent e90981f commit 965a1e0

File tree

9 files changed

+217
-92
lines changed

9 files changed

+217
-92
lines changed

build.gradle

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ dependencies {
4040
compile('org.springframework.boot:spring-boot-starter-aop')
4141
compile group: 'org.springframework', name: 'spring-tx', version: '4.3.12.RELEASE'
4242
compile group: 'org.springframework', name: 'spring-jdbc', version: '4.3.12.RELEASE'
43-
compile("org.springframework.boot:spring-boot-devtools")
44-
testCompile('org.springframework.boot:spring-boot-starter-test')
43+
testCompile('org.springframework.boot:spring-boot-starter-test')
44+
45+
// 热部署相关
46+
// compile("org.springframework.boot:spring-boot-devtools")
4547

4648
//数据库相关
4749
compile group: 'mysql', name: 'mysql-connector-java', version: '6.0.6'
@@ -64,6 +66,8 @@ dependencies {
6466

6567
//redis相关配置
6668
compile group: 'org.springframework.session', name: 'spring-session-data-redis', version: '1.3.1.RELEASE'
69+
//用于redis序列化用户
70+
compile group: 'com.esotericsoftware', name: 'kryo', version: '4.0.0'
6771

6872
//让thymeleaf解析标签没有闭合时通过
6973
compile group: 'net.sourceforge.nekohtml', name: 'nekohtml', version: '1.9.22'
@@ -73,4 +77,8 @@ dependencies {
7377

7478
//log4jdbc
7579
compile group: 'org.bgee.log4jdbc-log4j2', name: 'log4jdbc-log4j2-jdbc4.1', version: '1.16'
80+
81+
// https://mvnrepository.com/artifact/io.protostuff/protostuff-core
82+
compile group: 'io.protostuff', name: 'protostuff-runtime', version: '1.6.0'
83+
compile group: 'io.protostuff', name: 'protostuff-core', version: '1.6.0'
7684
}

src/main/java/com/linkinstars/springBootTemplate/bean/UserEntity.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,11 @@ public void setVal(String val) {
2525
this.val = val;
2626
}
2727

28+
@Override
29+
public String toString() {
30+
return "UserEntity{" +
31+
"id=" + id +
32+
", val='" + val + '\'' +
33+
'}';
34+
}
2835
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.linkinstars.springBootTemplate.config;
2+
3+
import com.linkinstars.springBootTemplate.util.ProtostuffSerializer;
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
import org.springframework.data.redis.connection.RedisConnectionFactory;
7+
import org.springframework.data.redis.core.RedisTemplate;
8+
import org.springframework.data.redis.serializer.StringRedisSerializer;
9+
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
10+
11+
/**
12+
* redisTemplate初始化,开启spring-session redis存储支持
13+
* @author LinkinStar
14+
*/
15+
@Configuration
16+
@EnableRedisHttpSession
17+
public class RedisConfig {
18+
19+
/**
20+
* redisTemplate 序列化使用的Serializeable, 存储二进制字节码, 所以自定义序列化类
21+
* @Rparam redisConnectionFactory
22+
* @return redisTemplate
23+
*/
24+
@Bean
25+
public RedisTemplate<Object, Object> protoStuffTemplate(RedisConnectionFactory redisConnectionFactory) {
26+
RedisTemplate<Object, Object> template = new RedisTemplate<>();
27+
template.setConnectionFactory(redisConnectionFactory);
28+
29+
// redis value使用的序列化器
30+
template.setValueSerializer(new ProtostuffSerializer());
31+
// redis key使用的序列化器
32+
template.setKeySerializer(new StringRedisSerializer());
33+
34+
template.afterPropertiesSet();
35+
return template;
36+
}
37+
}

src/main/java/com/linkinstars/springBootTemplate/config/RedisSessionConfig.java

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/main/java/com/linkinstars/springBootTemplate/controller/UserController.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,17 @@ public String test(HttpServletRequest request, @RequestParam(required = false) I
6969

7070

7171
//测试redis
72-
redisUtil.setString("xxx","xxx");
73-
System.out.println("redis数据获取为: " + redisUtil.getString("xxx"));
74-
redisUtil.delete("xxx");
75-
System.out.println("redis数据获取为: " + redisUtil.getString("xxx"));
72+
UserEntity user = new UserEntity();
73+
user.setId(1);
74+
user.setVal("xxx");
7675

77-
redisUtil.setHash("xxxx", "a", "1");
78-
redisUtil.setHash("xxxx", "b", "2");
79-
redisUtil.setHash("xxxx", "c", "3");
76+
redisUtil.set("xxx", user);
77+
Object object = redisUtil.get("xxx");
78+
UserEntity userTemp = (UserEntity) object;
8079

81-
System.out.println("redis中hash的数据为: " + redisUtil.getHash("xxxx","a"));
80+
System.out.println("redis数据获取为: " + userTemp);
81+
redisUtil.delete("xxx");
82+
System.out.println("redis删除数据之后获取为: " + redisUtil.get("xxx"));
8283

8384

8485
//测试事务回滚
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package com.linkinstars.springBootTemplate.util;
2+
3+
import com.esotericsoftware.kryo.Kryo;
4+
import com.esotericsoftware.kryo.io.Input;
5+
import com.esotericsoftware.kryo.io.Output;
6+
import org.slf4j.Logger;
7+
import org.slf4j.LoggerFactory;
8+
import org.springframework.data.redis.serializer.RedisSerializer;
9+
import org.springframework.data.redis.serializer.SerializationException;
10+
11+
import java.io.ByteArrayOutputStream;
12+
13+
/**
14+
* Kryo序列化工具
15+
* @param <T>
16+
*/
17+
public class KryoRedisSerializer<T> implements RedisSerializer<T> {
18+
19+
private static final Logger logger = LoggerFactory.getLogger(KryoRedisSerializer.class);
20+
21+
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
22+
23+
private static final ThreadLocal<Kryo> KRYOS = ThreadLocal.withInitial(Kryo::new);
24+
25+
private Class<T> clazz;
26+
27+
public KryoRedisSerializer(Class<T> clazz) {
28+
super();
29+
this.clazz = clazz;
30+
}
31+
32+
@Override
33+
public byte[] serialize(T t) throws SerializationException {
34+
if (t == null) {
35+
return EMPTY_BYTE_ARRAY;
36+
}
37+
38+
Kryo kryo = KRYOS.get();
39+
kryo.setReferences(false);
40+
kryo.register(clazz);
41+
42+
try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
43+
Output output = new Output(baos)) {
44+
kryo.writeClassAndObject(output, t);
45+
output.flush();
46+
return baos.toByteArray();
47+
} catch (Exception e) {
48+
logger.error(e.getMessage(), e);
49+
}
50+
51+
return EMPTY_BYTE_ARRAY;
52+
}
53+
54+
@Override
55+
public T deserialize(byte[] bytes) throws SerializationException {
56+
if (bytes == null || bytes.length <= 0) {
57+
return null;
58+
}
59+
60+
Kryo kryo = KRYOS.get();
61+
kryo.setReferences(false);
62+
kryo.register(clazz);
63+
64+
try (Input input = new Input(bytes)) {
65+
return (T) kryo.readClassAndObject(input);
66+
} catch (Exception e) {
67+
logger.error(e.getMessage(), e);
68+
}
69+
70+
return null;
71+
}
72+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.linkinstars.springBootTemplate.util;
2+
3+
import io.protostuff.LinkedBuffer;
4+
import io.protostuff.ProtostuffIOUtil;
5+
import io.protostuff.Schema;
6+
import io.protostuff.runtime.RuntimeSchema;
7+
import org.springframework.data.redis.serializer.RedisSerializer;
8+
import org.springframework.data.redis.serializer.SerializationException;
9+
10+
/**
11+
* ProtoStuff序列化工具
12+
* @author LinkinStar
13+
*/
14+
public class ProtostuffSerializer<T> implements RedisSerializer<T> {
15+
16+
private boolean isEmpty(byte[] data) {
17+
return (data == null || data.length == 0);
18+
}
19+
20+
private final Schema<ProtoWrapper> schema;
21+
22+
private final ProtoWrapper wrapper;
23+
24+
private final LinkedBuffer buffer;
25+
26+
public ProtostuffSerializer() {
27+
this.wrapper = new ProtoWrapper();
28+
this.schema = RuntimeSchema.getSchema(ProtoWrapper.class);
29+
this.buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
30+
}
31+
32+
@Override
33+
public byte[] serialize(Object t) throws SerializationException {
34+
if (t == null) {
35+
return new byte[0];
36+
}
37+
wrapper.data = t;
38+
try {
39+
return ProtostuffIOUtil.toByteArray(wrapper, schema, buffer);
40+
} finally {
41+
buffer.clear();
42+
}
43+
}
44+
45+
@Override
46+
public T deserialize(byte[] bytes) throws SerializationException {
47+
if (isEmpty(bytes)) {
48+
return null;
49+
}
50+
ProtoWrapper newMessage = schema.newMessage();
51+
ProtostuffIOUtil.mergeFrom(bytes, newMessage, schema);
52+
return (T) newMessage.data;
53+
}
54+
55+
private static class ProtoWrapper {
56+
private Object data;
57+
}
58+
}
Lines changed: 19 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,22 @@
11
package com.linkinstars.springBootTemplate.util;
22

33
import org.springframework.beans.factory.annotation.Autowired;
4-
import org.springframework.data.redis.core.StringRedisTemplate;
4+
import org.springframework.beans.factory.annotation.Qualifier;
5+
import org.springframework.data.redis.core.RedisTemplate;
6+
import org.springframework.stereotype.Component;
57

68
import java.util.concurrent.TimeUnit;
79

810
/**
911
* Redis操作工具类
1012
* @author LinkinStar
1113
*/
14+
@Component
1215
public class RedisUtil {
1316

14-
/**
15-
* RedisTemplate 使用的是 JdkSerializationRedisSerializer
16-
* StringRedisTemplate 使用的是 StringRedisSerializer
17-
* 之后可以通过构建redisTemplate来替换序列化的方式
18-
*/
19-
// @Autowired
20-
// private RedisTemplate<String, Object> redisTemplate;
21-
2217
@Autowired
23-
private StringRedisTemplate redisTemplate;
24-
18+
@Qualifier("protoStuffTemplate")
19+
private RedisTemplate protoStuffTemplate;
2520

2621
/**
2722
* 设置过期时间,单位秒
@@ -30,15 +25,15 @@ public class RedisUtil {
3025
* @return 成功:true,失败:false
3126
*/
3227
public boolean setExpireTime(String key, long timeout) {
33-
return redisTemplate.expire(key, timeout, TimeUnit.SECONDS);
28+
return protoStuffTemplate.expire(key, timeout, TimeUnit.SECONDS);
3429
}
3530

3631
/**
3732
* 通过键删除一个值
3833
* @param key 键的名称
3934
*/
4035
public void delete(String key) {
41-
redisTemplate.delete(key);
36+
protoStuffTemplate.delete(key);
4237
}
4338

4439
/**
@@ -47,63 +42,34 @@ public void delete(String key) {
4742
* @return 存在:true,不存在:false
4843
*/
4944
public boolean hasKey(String key) {
50-
return redisTemplate.hasKey(key);
45+
return protoStuffTemplate.hasKey(key);
5146
}
5247

5348
/**
54-
* 字符串存储
49+
* 数据存储
5550
* @param key 键
5651
* @param value 值
5752
*/
58-
public void setString(String key, String value) {
59-
redisTemplate.opsForValue().set(key, value);
53+
public void set(String key, Object value) {
54+
protoStuffTemplate.boundValueOps(key).set(value);
6055
}
6156

6257
/**
63-
* 字符串存储(同时设置超时时间)
58+
* 数据存储的同时设置过期时间
6459
* @param key 键
6560
* @param value 值
66-
* @param timeout 超时时间(以秒为单位)
61+
* @param expireTime 过期时间
6762
*/
68-
public void setStringAndExpireTime(String key, String value, long timeout) {
69-
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
63+
public void set(String key, Object value, Long expireTime) {
64+
protoStuffTemplate.boundValueOps(key).set(value, expireTime, TimeUnit.SECONDS);
7065
}
7166

7267
/**
73-
* 字符串取值
68+
* 数据取值
7469
* @param key 键
7570
* @return 查询成功:值,查询失败,null
7671
*/
77-
public String getString(String key) {
78-
return (String) redisTemplate.opsForValue().get(key);
79-
}
80-
81-
/**
82-
* 存储哈希表
83-
* @param key 整个哈希表的键
84-
* @param field 表中的键
85-
* @param value 表中的值
86-
*/
87-
public void setHash(String key, String field, Object value) {
88-
redisTemplate.opsForHash().put(key, field, value);
89-
}
90-
91-
/**
92-
* 获取哈希表
93-
* @param key 整个哈希表的键
94-
* @param field 表中的键
95-
* @return 查询成功:值,查询失败,null
96-
*/
97-
public Object getHash(String key, String field) {
98-
return redisTemplate.opsForHash().get(key, field);
99-
}
100-
101-
/**
102-
* 删除哈希表中的某个元素
103-
* @param key 整个哈希表的键
104-
* @param fields 表中的键
105-
*/
106-
public void deleteHash(String key, Object... fields) {
107-
redisTemplate.opsForHash().delete(key, fields);
72+
public Object get(String key) {
73+
return protoStuffTemplate.boundValueOps(key).get();
10874
}
10975
}

0 commit comments

Comments
 (0)