From 260ef5de8a0864a04e5d455116cf426669d7c098 Mon Sep 17 00:00:00 2001 From: "ken.lj" Date: Thu, 9 Aug 2018 16:07:56 +0800 Subject: [PATCH] Fixes #2178, leave jdk standard classes to kryo itself. --- .../support/SerializableClassRegistry.java | 23 +++++++++++++++---- .../SerializableClassRegistryTest.java | 8 +++---- .../common/serialize/fst/FstFactory.java | 5 +--- .../common/serialize/kryo/CompatibleKryo.java | 18 +++++++++++---- .../kryo/utils/AbstractKryoFactory.java | 16 ++++++++----- .../serialize/kryo/utils/ReflectionUtils.java | 4 ++++ 6 files changed, 50 insertions(+), 24 deletions(-) diff --git a/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistry.java b/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistry.java index dd7185936f5..2ebb3a3c7fd 100644 --- a/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistry.java +++ b/dubbo-serialization/dubbo-serialization-api/src/main/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistry.java @@ -16,21 +16,34 @@ */ package org.apache.dubbo.common.serialize.support; -import java.util.LinkedHashSet; -import java.util.Set; +import com.esotericsoftware.kryo.Serializer; + +import java.util.LinkedHashMap; +import java.util.Map; public abstract class SerializableClassRegistry { - private static final Set registrations = new LinkedHashSet(); + + private static final Map registrations = new LinkedHashMap<>(); /** * only supposed to be called at startup time */ public static void registerClass(Class clazz) { - registrations.add(clazz); + registerClass(clazz, null); + } + + /** + * only supposed to be called at startup time + */ + public static void registerClass(Class clazz, Serializer serializer) { + if (clazz == null) { + throw new IllegalArgumentException("Class registered to kryo cannot be null!"); + } + registrations.put(clazz, serializer); } - public static Set getRegisteredClasses() { + public static Map getRegisteredClasses() { return registrations; } } diff --git a/dubbo-serialization/dubbo-serialization-api/src/test/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistryTest.java b/dubbo-serialization/dubbo-serialization-api/src/test/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistryTest.java index f471bc451a9..efde85c6bc2 100644 --- a/dubbo-serialization/dubbo-serialization-api/src/test/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistryTest.java +++ b/dubbo-serialization/dubbo-serialization-api/src/test/java/org/apache/dubbo/common/serialize/support/SerializableClassRegistryTest.java @@ -18,9 +18,9 @@ import org.junit.Test; -import java.util.Set; +import java.util.Map; -import static org.hamcrest.Matchers.hasSize; +import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; public class SerializableClassRegistryTest { @@ -29,8 +29,8 @@ public void testAddClasses() { SerializableClassRegistry.registerClass(A.class); SerializableClassRegistry.registerClass(B.class); - Set registeredClasses = SerializableClassRegistry.getRegisteredClasses(); - assertThat(registeredClasses, hasSize(2)); + Map registeredClasses = SerializableClassRegistry.getRegisteredClasses(); + assertThat(registeredClasses.size(), equalTo(2)); } private class A { diff --git a/dubbo-serialization/dubbo-serialization-fst/src/main/java/org/apache/dubbo/common/serialize/fst/FstFactory.java b/dubbo-serialization/dubbo-serialization-fst/src/main/java/org/apache/dubbo/common/serialize/fst/FstFactory.java index feb9ce4646b..6329d1ecb7d 100644 --- a/dubbo-serialization/dubbo-serialization-fst/src/main/java/org/apache/dubbo/common/serialize/fst/FstFactory.java +++ b/dubbo-serialization/dubbo-serialization-fst/src/main/java/org/apache/dubbo/common/serialize/fst/FstFactory.java @@ -17,7 +17,6 @@ package org.apache.dubbo.common.serialize.fst; import org.apache.dubbo.common.serialize.support.SerializableClassRegistry; - import org.nustaq.serialization.FSTConfiguration; import org.nustaq.serialization.FSTObjectInput; import org.nustaq.serialization.FSTObjectOutput; @@ -37,9 +36,7 @@ public static FstFactory getDefaultFactory() { } public FstFactory() { - for (Class clazz : SerializableClassRegistry.getRegisteredClasses()) { - conf.registerClass(clazz); - } + SerializableClassRegistry.getRegisteredClasses().keySet().forEach(conf::registerClass); } public FSTObjectOutput getObjectOutput(OutputStream outputStream) { diff --git a/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/CompatibleKryo.java b/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/CompatibleKryo.java index dcd000767b0..ba854e5381b 100644 --- a/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/CompatibleKryo.java +++ b/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/CompatibleKryo.java @@ -16,13 +16,12 @@ */ package org.apache.dubbo.common.serialize.kryo; -import org.apache.dubbo.common.logger.Logger; -import org.apache.dubbo.common.logger.LoggerFactory; -import org.apache.dubbo.common.serialize.kryo.utils.ReflectionUtils; - import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.serializers.JavaSerializer; +import org.apache.dubbo.common.logger.Logger; +import org.apache.dubbo.common.logger.LoggerFactory; +import org.apache.dubbo.common.serialize.kryo.utils.ReflectionUtils; public class CompatibleKryo extends Kryo { @@ -34,7 +33,16 @@ public Serializer getDefaultSerializer(Class type) { throw new IllegalArgumentException("type cannot be null."); } - if (!type.isArray() && !type.isEnum() && !ReflectionUtils.checkZeroArgConstructor(type)) { + /** + * Kryo requires every class to provide a zero argument constructor. For any class does not match this condition, kryo have two ways: + * 1. Use JavaSerializer, + * 2. Set 'kryo.setInstantiatorStrategy(new DefaultInstantiatorStrategy(new StdInstantiatorStrategy()));', StdInstantiatorStrategy can generate an instance bypassing the constructor. + * + * In practice, it's not possible for Dubbo users to register kryo Serializer for every customized class. So in most cases, customized classes with/without zero argument constructor will + * default to the default serializer. + * It is the responsibility of kryo to handle with every standard jdk classes, so we will just escape these classes. + */ + if (!ReflectionUtils.isJdk(type) && !type.isArray() && !type.isEnum() && !ReflectionUtils.checkZeroArgConstructor(type)) { if (logger.isWarnEnabled()) { logger.warn(type + " has no zero-arg constructor and this will affect the serialization performance"); } diff --git a/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/AbstractKryoFactory.java b/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/AbstractKryoFactory.java index ca0abad42fa..523b59f7b30 100644 --- a/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/AbstractKryoFactory.java +++ b/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/AbstractKryoFactory.java @@ -16,10 +16,8 @@ */ package org.apache.dubbo.common.serialize.kryo.utils; -import org.apache.dubbo.common.serialize.kryo.CompatibleKryo; -import org.apache.dubbo.common.serialize.support.SerializableClassRegistry; - import com.esotericsoftware.kryo.Kryo; +import com.esotericsoftware.kryo.Serializer; import com.esotericsoftware.kryo.pool.KryoFactory; import com.esotericsoftware.kryo.serializers.DefaultSerializers; import de.javakaffee.kryoserializers.ArraysAsListSerializer; @@ -31,6 +29,8 @@ import de.javakaffee.kryoserializers.URISerializer; import de.javakaffee.kryoserializers.UUIDSerializer; import de.javakaffee.kryoserializers.UnmodifiableCollectionsSerializer; +import org.apache.dubbo.common.serialize.kryo.CompatibleKryo; +import org.apache.dubbo.common.serialize.support.SerializableClassRegistry; import java.lang.reflect.InvocationHandler; import java.math.BigDecimal; @@ -134,9 +134,13 @@ public Kryo create() { kryo.register(clazz); } - for (Class clazz : SerializableClassRegistry.getRegisteredClasses()) { - kryo.register(clazz); - } + SerializableClassRegistry.getRegisteredClasses().forEach((clazz, ser) -> { + if (ser == null) { + kryo.register(clazz); + } else { + kryo.register(clazz, (Serializer) ser); + } + }); return kryo; } diff --git a/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/ReflectionUtils.java b/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/ReflectionUtils.java index 473685e7b80..7c3b45a816d 100644 --- a/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/ReflectionUtils.java +++ b/dubbo-serialization/dubbo-serialization-kryo/src/main/java/org/apache/dubbo/common/serialize/kryo/utils/ReflectionUtils.java @@ -26,4 +26,8 @@ public static boolean checkZeroArgConstructor(Class clazz) { return false; } } + + public static boolean isJdk(Class clazz) { + return clazz.getName().startsWith("java.") || clazz.getName().startsWith("javax."); + } }