@@ -108,15 +108,48 @@ Java 自身的序列化方式具有以下缺点:
108108示例:
109109
110110``` java
111+ import org.nustaq.serialization.FSTConfiguration ;
112+
113+ import java.io.IOException ;
114+ import java.nio.charset.StandardCharsets ;
115+ import java.util.Base64 ;
116+
111117public class FstDemo {
112118
113119 private static FSTConfiguration DEFAULT_CONFIG = FSTConfiguration . createDefaultConfiguration();
114120
115- public static <T > byte [] serialize (T obj ) {
121+ /**
122+ * 将对象序列化为 byte 数组
123+ *
124+ * @param obj 任意对象
125+ * @param <T> 对象的类型
126+ * @return 序列化后的 byte 数组
127+ */
128+ public static <T > byte [] writeToBytes (T obj ) {
116129 return DEFAULT_CONFIG . asByteArray(obj);
117130 }
118131
119- public static <T > T deserialize (byte [] bytes , Class<T > clazz ) throws IOException {
132+ /**
133+ * 将对象序列化为 byte 数组后,再使用 Base64 编码
134+ *
135+ * @param obj 任意对象
136+ * @param <T> 对象的类型
137+ * @return 序列化后的字符串
138+ */
139+ public static <T > String writeToString (T obj ) {
140+ byte [] bytes = writeToBytes(obj);
141+ return new String (Base64 . getEncoder(). encode(bytes), StandardCharsets . UTF_8 );
142+ }
143+
144+ /**
145+ * 将 byte 数组反序列化为原对象
146+ *
147+ * @param bytes {@link #writeToBytes} 方法序列化后的 byte 数组
148+ * @param clazz 原对象的类型
149+ * @param <T> 原对象的类型
150+ * @return 原对象
151+ */
152+ public static <T > T readFromBytes (byte [] bytes , Class<T > clazz ) throws IOException {
120153 Object obj = DEFAULT_CONFIG . asObject(bytes);
121154 if (clazz. isInstance(obj)) {
122155 return (T ) obj;
@@ -125,19 +158,171 @@ public class FstDemo {
125158 }
126159 }
127160
161+ /**
162+ * 将字符串反序列化为原对象,先使用 Base64 解码
163+ *
164+ * @param str {@link #writeToString} 方法序列化后的字符串
165+ * @param clazz 原对象的类型
166+ * @param <T> 原对象的类型
167+ * @return 原对象
168+ */
169+ public static <T > T readFromString (String str , Class<T > clazz ) throws IOException {
170+ byte [] bytes = str. getBytes(StandardCharsets . UTF_8 );
171+ return readFromBytes(Base64 . getDecoder(). decode(bytes), clazz);
172+ }
173+
128174}
129175```
130176
131177测试:
132178
133179``` java
134- // 序列化
135- byte [] bytes = JdkSerializeDemo . serialize(oldBean);
136- // 反序列化
137- TestBean newBean = JdkSerializeDemo . deserialize(bytes, TestBean . class);
180+ long begin = System . currentTimeMillis();
181+ for (int i = 0 ; i < BATCH_SIZE ; i++ ) {
182+ TestBean oldBean = BeanUtils . initJdk8Bean();
183+ byte [] bytes = FstDemo . writeToBytes(oldBean);
184+ TestBean newBean = FstDemo . readFromBytes(bytes, TestBean . class);
185+ }
186+ long end = System . currentTimeMillis();
187+ System . out. printf(" FST 序列化/反序列化耗时:%s" , (end - begin));
138188```
139189
140- ## TODO
190+ ## Kryo 应用
191+
192+ ### 引入依赖
193+
194+ ``` xml
195+ <dependency >
196+ <groupId >com.esotericsoftware</groupId >
197+ <artifactId >kryo</artifactId >
198+ <version >5.0.0-RC4</version >
199+ </dependency >
200+ ```
201+
202+ ### Kryo API
203+
204+ 示例:
205+
206+ ``` java
207+ import com.esotericsoftware.kryo.Kryo ;
208+ import com.esotericsoftware.kryo.io.Input ;
209+ import com.esotericsoftware.kryo.io.Output ;
210+ import com.esotericsoftware.kryo.util.DefaultInstantiatorStrategy ;
211+ import org.objenesis.strategy.StdInstantiatorStrategy ;
212+
213+ import java.io.ByteArrayInputStream ;
214+ import java.io.ByteArrayOutputStream ;
215+ import java.nio.charset.StandardCharsets ;
216+ import java.util.Base64 ;
217+
218+ public class KryoDemo {
219+
220+ // 每个线程的 Kryo 实例
221+ private static final ThreadLocal<Kryo > kryoLocal = ThreadLocal . withInitial(() - > {
222+ Kryo kryo = new Kryo ();
223+
224+ /**
225+ * 不要轻易改变这里的配置!更改之后,序列化的格式就会发生变化,
226+ * 上线的同时就必须清除 Redis 里的所有缓存,
227+ * 否则那些缓存再回来反序列化的时候,就会报错
228+ */
229+ // 支持对象循环引用(否则会栈溢出)
230+ kryo. setReferences(true ); // 默认值就是 true,添加此行的目的是为了提醒维护者,不要改变这个配置
231+
232+ // 不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册)
233+ kryo. setRegistrationRequired(false ); // 默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
234+
235+ // Fix the NPE bug when deserializing Collections.
236+ ((DefaultInstantiatorStrategy ) kryo. getInstantiatorStrategy())
237+ .setFallbackInstantiatorStrategy(new StdInstantiatorStrategy ());
238+
239+ return kryo;
240+ });
241+
242+ /**
243+ * 获得当前线程的 Kryo 实例
244+ *
245+ * @return 当前线程的 Kryo 实例
246+ */
247+ public static Kryo getInstance () {
248+ return kryoLocal. get();
249+ }
250+
251+ /**
252+ * 将对象序列化为 byte 数组
253+ *
254+ * @param obj 任意对象
255+ * @param <T> 对象的类型
256+ * @return 序列化后的 byte 数组
257+ */
258+ public static <T > byte [] writeToBytes (T obj ) {
259+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream ();
260+ Output output = new Output (byteArrayOutputStream);
261+
262+ Kryo kryo = getInstance();
263+ kryo. writeObject(output, obj);
264+ output. flush();
265+
266+ return byteArrayOutputStream. toByteArray();
267+ }
268+
269+ /**
270+ * 将对象序列化为 byte 数组后,再使用 Base64 编码
271+ *
272+ * @param obj 任意对象
273+ * @param <T> 对象的类型
274+ * @return 序列化后的字符串
275+ */
276+ public static <T > String writeToString (T obj ) {
277+ byte [] bytes = writeToBytes(obj);
278+ return new String (Base64 . getEncoder(). encode(bytes), StandardCharsets . UTF_8 );
279+ }
280+
281+ /**
282+ * 将 byte 数组反序列化为原对象
283+ *
284+ * @param bytes {@link #writeToBytes} 方法序列化后的 byte 数组
285+ * @param clazz 原对象的类型
286+ * @param <T> 原对象的类型
287+ * @return 原对象
288+ */
289+ @SuppressWarnings (" unchecked" )
290+ public static <T > T readFromBytes (byte [] bytes , Class<T > clazz ) {
291+ ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream (bytes);
292+ Input input = new Input (byteArrayInputStream);
293+
294+ Kryo kryo = getInstance();
295+ return (T ) kryo. readObject(input, clazz);
296+ }
297+
298+ /**
299+ * 将字符串反序列化为原对象,先使用 Base64 解码
300+ *
301+ * @param str {@link #writeToString} 方法序列化后的字符串
302+ * @param clazz 原对象的类型
303+ * @param <T> 原对象的类型
304+ * @return 原对象
305+ */
306+ public static <T > T readFromString (String str , Class<T > clazz ) {
307+ byte [] bytes = str. getBytes(StandardCharsets . UTF_8 );
308+ return readFromBytes(Base64 . getDecoder(). decode(bytes), clazz);
309+ }
310+
311+ }
312+ ```
313+
314+ 测试:
315+
316+ ``` java
317+ long begin = System . currentTimeMillis();
318+ for (int i = 0 ; i < BATCH_SIZE ; i++ ) {
319+ TestBean oldBean = BeanUtils . initJdk8Bean();
320+ byte [] bytes = KryoDemo . writeToBytes(oldBean);
321+ TestBean newBean = KryoDemo . readFromBytes(bytes, TestBean . class);
322+ }
323+ long end = System . currentTimeMillis();
324+ System . out. printf(" Kryo 序列化/反序列化耗时:%s" , (end - begin));
325+ ```
141326
142327## 参考资料
143328
0 commit comments