Skip to content

Commit bd88a39

Browse files
committed
[javalib-io-binary] 二进制序列化/反序列化工具示例
1 parent 4a4e005 commit bd88a39

File tree

7 files changed

+229
-19
lines changed

7 files changed

+229
-19
lines changed

javalib-io-binary/pom.xml

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,6 @@
3232
<version>5.0.0-RC4</version>
3333
</dependency>
3434

35-
<dependency>
36-
<groupId>org.projectlombok</groupId>
37-
<artifactId>lombok</artifactId>
38-
</dependency>
3935
<dependency>
4036
<groupId>io.github.dunwu</groupId>
4137
<artifactId>dunwu-common</artifactId>

javalib-io-binary/src/main/java/io/github/dunwu/javalib/io/FstDemo.java

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import org.nustaq.serialization.FSTConfiguration;
44

55
import java.io.IOException;
6+
import java.nio.charset.StandardCharsets;
7+
import java.util.Base64;
68

79
/**
8-
* fast-serialization lib Demo
10+
* <a href="https://github.com/RuedigerMoeller/fast-serialization">FST</a> 序列化/反序列化示例
911
*
1012
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
1113
* @see <a href="https://github.com/RuedigerMoeller/fast-serialization">FST</a>
@@ -15,11 +17,38 @@ public class FstDemo {
1517

1618
private static FSTConfiguration DEFAULT_CONFIG = FSTConfiguration.createDefaultConfiguration();
1719

18-
public static <T> byte[] serialize(T obj) {
20+
/**
21+
* 将对象序列化为 byte 数组
22+
*
23+
* @param obj 任意对象
24+
* @param <T> 对象的类型
25+
* @return 序列化后的 byte 数组
26+
*/
27+
public static <T> byte[] writeToBytes(T obj) {
1928
return DEFAULT_CONFIG.asByteArray(obj);
2029
}
2130

22-
public static <T> T deserialize(byte[] bytes, Class<T> clazz) throws IOException {
31+
/**
32+
* 将对象序列化为 byte 数组后,再使用 Base64 编码
33+
*
34+
* @param obj 任意对象
35+
* @param <T> 对象的类型
36+
* @return 序列化后的字符串
37+
*/
38+
public static <T> String writeToString(T obj) {
39+
byte[] bytes = writeToBytes(obj);
40+
return new String(Base64.getEncoder().encode(bytes), StandardCharsets.UTF_8);
41+
}
42+
43+
/**
44+
* 将 byte 数组反序列化为原对象
45+
*
46+
* @param bytes {@link #writeToBytes} 方法序列化后的 byte 数组
47+
* @param clazz 原对象的类型
48+
* @param <T> 原对象的类型
49+
* @return 原对象
50+
*/
51+
public static <T> T readFromBytes(byte[] bytes, Class<T> clazz) throws IOException {
2352
Object obj = DEFAULT_CONFIG.asObject(bytes);
2453
if (clazz.isInstance(obj)) {
2554
return (T) obj;
@@ -28,4 +57,17 @@ public static <T> T deserialize(byte[] bytes, Class<T> clazz) throws IOException
2857
}
2958
}
3059

60+
/**
61+
* 将字符串反序列化为原对象,先使用 Base64 解码
62+
*
63+
* @param str {@link #writeToString} 方法序列化后的字符串
64+
* @param clazz 原对象的类型
65+
* @param <T> 原对象的类型
66+
* @return 原对象
67+
*/
68+
public static <T> T readFromString(String str, Class<T> clazz) throws IOException {
69+
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
70+
return readFromBytes(Base64.getDecoder().decode(bytes), clazz);
71+
}
72+
3173
}

javalib-io-binary/src/main/java/io/github/dunwu/javalib/io/JdkSerializeDemo.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package io.github.dunwu.javalib.io;
22

33
import java.io.*;
4+
import java.nio.charset.StandardCharsets;
5+
import java.util.Base64;
46

57
/**
68
* JDK 默认序列化、反序列化机制示例
@@ -10,7 +12,14 @@
1012
*/
1113
public class JdkSerializeDemo {
1214

13-
public static <T> byte[] serialize(T obj) throws IOException {
15+
/**
16+
* 将对象序列化为 byte 数组
17+
*
18+
* @param obj 任意对象
19+
* @param <T> 对象的类型
20+
* @return 序列化后的 byte 数组
21+
*/
22+
public static <T> byte[] writeToBytes(T obj) throws IOException {
1423
ByteArrayOutputStream baos = new ByteArrayOutputStream();
1524
ObjectOutputStream oos = new ObjectOutputStream(baos);
1625
oos.writeObject(obj);
@@ -20,7 +29,27 @@ public static <T> byte[] serialize(T obj) throws IOException {
2029
return bytes;
2130
}
2231

23-
public static <T> T deserialize(byte[] bytes, Class<T> clazz) throws IOException, ClassNotFoundException {
32+
/**
33+
* 将对象序列化为 byte 数组后,再使用 Base64 编码
34+
*
35+
* @param obj 任意对象
36+
* @param <T> 对象的类型
37+
* @return 序列化后的字符串
38+
*/
39+
public static <T> String writeToString(T obj) throws IOException {
40+
byte[] bytes = writeToBytes(obj);
41+
return new String(Base64.getEncoder().encode(bytes), StandardCharsets.UTF_8);
42+
}
43+
44+
/**
45+
* 将 byte 数组反序列化为原对象
46+
*
47+
* @param bytes {@link #writeToBytes} 方法序列化后的 byte 数组
48+
* @param clazz 原对象的类型
49+
* @param <T> 原对象的类型
50+
* @return 原对象
51+
*/
52+
public static <T> T readFromBytes(byte[] bytes, Class<T> clazz) throws IOException, ClassNotFoundException {
2453
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
2554
ObjectInputStream ois = new ObjectInputStream(bais);
2655
Object obj = ois.readObject();
@@ -33,4 +62,17 @@ public static <T> T deserialize(byte[] bytes, Class<T> clazz) throws IOException
3362
}
3463
}
3564

65+
/**
66+
* 将字符串反序列化为原对象,先使用 Base64 解码
67+
*
68+
* @param str {@link #writeToString} 方法序列化后的字符串
69+
* @param clazz 原对象的类型
70+
* @param <T> 原对象的类型
71+
* @return 原对象
72+
*/
73+
public static <T> T readFromString(String str, Class<T> clazz) throws IOException, ClassNotFoundException {
74+
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
75+
return readFromBytes(Base64.getDecoder().decode(bytes), clazz);
76+
}
77+
3678
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
package io.github.dunwu.javalib.io;
2+
3+
import com.esotericsoftware.kryo.Kryo;
4+
import com.esotericsoftware.kryo.io.Input;
5+
import com.esotericsoftware.kryo.io.Output;
6+
import com.esotericsoftware.kryo.util.DefaultInstantiatorStrategy;
7+
import org.objenesis.strategy.StdInstantiatorStrategy;
8+
9+
import java.io.ByteArrayInputStream;
10+
import java.io.ByteArrayOutputStream;
11+
import java.nio.charset.StandardCharsets;
12+
import java.util.Base64;
13+
14+
/**
15+
* <a href="https://github.com/EsotericSoftware/kryo">Kyro</a> 序列化/反序列化示例
16+
*
17+
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
18+
* @author <a href="https://www.cnblogs.com/hntyzgn/p/7122709.html">Kryo 使用指南</a>
19+
* @since 2019-11-26
20+
*/
21+
public class KryoDemo {
22+
23+
// 每个线程的 Kryo 实例
24+
private static final ThreadLocal<Kryo> kryoLocal = ThreadLocal.withInitial(() -> {
25+
Kryo kryo = new Kryo();
26+
27+
/**
28+
* 不要轻易改变这里的配置!更改之后,序列化的格式就会发生变化,
29+
* 上线的同时就必须清除 Redis 里的所有缓存,
30+
* 否则那些缓存再回来反序列化的时候,就会报错
31+
*/
32+
//支持对象循环引用(否则会栈溢出)
33+
kryo.setReferences(true); //默认值就是 true,添加此行的目的是为了提醒维护者,不要改变这个配置
34+
35+
//不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册)
36+
kryo.setRegistrationRequired(false); //默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
37+
38+
//Fix the NPE bug when deserializing Collections.
39+
((DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy())
40+
.setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
41+
42+
return kryo;
43+
});
44+
45+
/**
46+
* 获得当前线程的 Kryo 实例
47+
*
48+
* @return 当前线程的 Kryo 实例
49+
*/
50+
public static Kryo getInstance() {
51+
return kryoLocal.get();
52+
}
53+
54+
/**
55+
* 将对象序列化为 byte 数组
56+
*
57+
* @param obj 任意对象
58+
* @param <T> 对象的类型
59+
* @return 序列化后的 byte 数组
60+
*/
61+
public static <T> byte[] writeToBytes(T obj) {
62+
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
63+
Output output = new Output(byteArrayOutputStream);
64+
65+
Kryo kryo = getInstance();
66+
kryo.writeObject(output, obj);
67+
output.flush();
68+
69+
return byteArrayOutputStream.toByteArray();
70+
}
71+
72+
/**
73+
* 将对象序列化为 byte 数组后,再使用 Base64 编码
74+
*
75+
* @param obj 任意对象
76+
* @param <T> 对象的类型
77+
* @return 序列化后的字符串
78+
*/
79+
public static <T> String writeToString(T obj) {
80+
byte[] bytes = writeToBytes(obj);
81+
return new String(Base64.getEncoder().encode(bytes), StandardCharsets.UTF_8);
82+
}
83+
84+
/**
85+
* 将 byte 数组反序列化为原对象
86+
*
87+
* @param bytes {@link #writeToBytes} 方法序列化后的 byte 数组
88+
* @param clazz 原对象的类型
89+
* @param <T> 原对象的类型
90+
* @return 原对象
91+
*/
92+
@SuppressWarnings("unchecked")
93+
public static <T> T readFromBytes(byte[] bytes, Class<T> clazz) {
94+
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
95+
Input input = new Input(byteArrayInputStream);
96+
97+
Kryo kryo = getInstance();
98+
return (T) kryo.readObject(input, clazz);
99+
}
100+
101+
/**
102+
* 将字符串反序列化为原对象,先使用 Base64 解码
103+
*
104+
* @param str {@link #writeToString} 方法序列化后的字符串
105+
* @param clazz 原对象的类型
106+
* @param <T> 原对象的类型
107+
* @return 原对象
108+
*/
109+
public static <T> T readFromString(String str, Class<T> clazz) {
110+
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
111+
return readFromBytes(Base64.getDecoder().decode(bytes), clazz);
112+
}
113+
114+
}

javalib-io-binary/src/test/java/io/github/dunwu/javalib/io/bean/BeanUtils.java renamed to javalib-io-binary/src/main/java/io/github/dunwu/javalib/io/bean/BeanUtils.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.github.dunwu.javalib.io.bean;
22

3-
import java.sql.Date;
3+
import io.github.dunwu.util.time.DateExtUtils;
4+
45
import java.time.LocalDate;
56
import java.time.LocalDateTime;
67
import java.util.*;
@@ -14,15 +15,14 @@ public class BeanUtils {
1415
public static TestBean initJdk8Bean() {
1516
String[] strArray = { "a", "b", "c" };
1617
Integer[] intArray = { 1, 2, 3, 4, 5 };
17-
List<Integer> intList = new ArrayList<>();
18-
intList.addAll(Arrays.asList(intArray));
18+
List<Integer> intList = new ArrayList<>(Arrays.asList(intArray));
1919
Map<String, Object> map = new HashMap<>();
2020
map.put("name", "jack");
2121
map.put("age", 18);
2222
map.put("length", 175.3f);
2323
TestBean bean = new TestBean();
24-
Date date = Date.valueOf("2019-11-22");
2524
LocalDateTime localDateTime = LocalDateTime.of(2000, 1, 1, 12, 0, 0);
25+
Date date = DateExtUtils.localDateTime2Date(localDateTime);
2626
LocalDate localDate = LocalDate.of(1949, 10, 1);
2727
bean.setI1(10).setI2(1024).setF1(0.5f).setD1(100.0)
2828
.setDate1(date).setDate2(localDateTime).setDate3(localDate)

javalib-io-binary/src/test/java/io/github/dunwu/javalib/io/bean/TestBean.java renamed to javalib-io-binary/src/main/java/io/github/dunwu/javalib/io/bean/TestBean.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class TestBean implements Serializable {
5050

5151
private Map<String, Object> map;
5252

53-
public static enum Color {
53+
public enum Color {
5454
RED,
5555
YELLOW,
5656
BLUE

javalib-io-binary/src/test/java/io/github/dunwu/javalib/io/SerializeTest.java renamed to javalib-io-binary/src/test/java/io/github/dunwu/javalib/io/SerializePerformanceTest.java

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99
import static org.assertj.core.api.Assertions.assertThat;
1010

1111
/**
12+
* 序列化、反序列化性能测试
13+
*
1214
* @author <a href="mailto:forbreak@163.com">Zhang Peng</a>
1315
* @since 2019-11-22
1416
*/
15-
public class SerializeTest {
17+
public class SerializePerformanceTest {
1618

1719
private static final int BATCH_SIZE = 100000;
1820

@@ -21,9 +23,9 @@ public void testJdkSerialize() throws IOException, ClassNotFoundException {
2123
long begin = System.currentTimeMillis();
2224
for (int i = 0; i < BATCH_SIZE; i++) {
2325
TestBean oldBean = BeanUtils.initJdk8Bean();
24-
byte[] bytes = JdkSerializeDemo.serialize(oldBean);
26+
byte[] bytes = JdkSerializeDemo.writeToBytes(oldBean);
2527
assertThat(bytes).isNotEmpty();
26-
TestBean newBean = JdkSerializeDemo.deserialize(bytes, TestBean.class);
28+
TestBean newBean = JdkSerializeDemo.readFromBytes(bytes, TestBean.class);
2729
assertThat(newBean).isNotNull();
2830
}
2931
long end = System.currentTimeMillis();
@@ -35,13 +37,27 @@ public void testFst() throws IOException {
3537
long begin = System.currentTimeMillis();
3638
for (int i = 0; i < BATCH_SIZE; i++) {
3739
TestBean oldBean = BeanUtils.initJdk8Bean();
38-
byte[] bytes = FstDemo.serialize(oldBean);
40+
byte[] bytes = FstDemo.writeToBytes(oldBean);
3941
assertThat(bytes).isNotEmpty();
40-
TestBean newBean = FstDemo.deserialize(bytes, TestBean.class);
42+
TestBean newBean = FstDemo.readFromBytes(bytes, TestBean.class);
4143
assertThat(newBean).isNotNull();
4244
}
4345
long end = System.currentTimeMillis();
4446
System.out.printf("FST 序列化/反序列化耗时:%s", (end - begin));
4547
}
4648

49+
@Test
50+
public void testKryo() throws IOException {
51+
long begin = System.currentTimeMillis();
52+
for (int i = 0; i < BATCH_SIZE; i++) {
53+
TestBean oldBean = BeanUtils.initJdk8Bean();
54+
byte[] bytes = KryoDemo.writeToBytes(oldBean);
55+
assertThat(bytes).isNotEmpty();
56+
TestBean newBean = KryoDemo.readFromBytes(bytes, TestBean.class);
57+
assertThat(newBean).isNotNull();
58+
}
59+
long end = System.currentTimeMillis();
60+
System.out.printf("Kryo 序列化/反序列化耗时:%s", (end - begin));
61+
}
62+
4763
}

0 commit comments

Comments
 (0)