赞
踩
dubbo
调用接口的时候,莫名其妙出现java.lang.ClassCastException: java.util.HashMap cannot be cast to xxxx
异常dubbo
接口返回的不是xxxx
对象,而是HashMap
dubbo
的反序列化机制默认是hessian2
SerializerFactory
类的getDeserializer()
方法try {
// Class cl = Class.forName(type, false, _loader);
Class cl = loadSerializedClass(type);
deserializer = getDeserializer(cl);
} catch (Exception e) {
log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + _loader + ":\n" + e);
_typeNotFoundDeserializerMap.put(type, PRESENT);
log.log(Level.FINER, e.toString(), e);
_unrecognizedTypeCache.put(type, new AtomicLong(1L));
}
deserializer = getDeserializer(cl);
这一行代码抛了异常,所以能看到日志输出log.warning("Hessian/Burlap: '" + type + "' is an unknown class in " + _loader + ":\n" + e);
Class.forName
,确实会报java.lang.ClassNotFoundException
异常hessian2
的类加载器是哪个org.apache.dubbo.common.serialize.hessian2.Hessian2SerializerFactory
这个类public class Hessian2SerializerFactory extends SerializerFactory {
@Override
public ClassLoader getClassLoader() {
return Thread.currentThread().getContextClassLoader();
}
}
Hessian2
重写了类加载器,为了观察这是哪个类加载器,增加日志输出public class Hessian2SerializerFactory extends SerializerFactory {
@Override
public ClassLoader getClassLoader() {
ClassLoader classLoaderTest = Thread.currentThread().getContextClassLoader();
loadClass(classLoaderTest, "com.xxxx");
ClassLoader parent = classLoaderTest.getParent();
while(parent!=null) {
loadClass(classLoaderTest, "com.xxxx");
parent = parent.getParent();
}
return classLoaderTest;
}
private void loadClass(ClassLoader classLoader, String className) {
try {
classLoader.loadClass(className);
log.info("load success: {}", classLoader.getClass().getName());
} catch (ClassNotFoundException e) {
log.info("load fail: {}", classLoader.getClass().getName());
}
}
}
org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader
和org.springframework.boot.loader.LaunchedURLClassLoader
,两个类加载器都是Spring
的jdk.internal.loader.ClassLoaders.AppClassLoader
dubbo
消费者在反序列化的时候,由于加载不到这个类,所以返回的对象按HashMap
处理org.springframework.util.ClassUtils
工具类的getDefaultClassLoader()
方法@Nullable
public static ClassLoader getDefaultClassLoader() {
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
}
catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
if (cl == null) {
// getClassLoader() returning null indicates the bootstrap ClassLoader
try {
cl = ClassLoader.getSystemClassLoader();
}
catch (Throwable ex) {
// Cannot access system ClassLoader - oh well, maybe the caller can live with null...
}
}
}
return cl;
}
Thread.currentThread().getContextClassLoader()
返回的是JDK类加载器ClassUtils.class.getClassLoader()
代替 @Override
public ClassLoader getClassLoader() {
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
if(Objects.nonNull(classLoader) && classLoader.getClass().getName().contains("spring")) {
return classLoader;
}
ClassLoader classLoaderNew = ClassUtils.class.getClassLoader();
log.info("classLoader is wrong: {}, change to: {}", classLoader, classLoaderNew);
return classLoaderNew;
}
[2023-12-20 18:56:48.683] [INFO] [ForkJoinPool.commonPool-worker-84]c.m.v.i.d.h.xxxxHessian2SerializerFactory[56][]- classLoader is wrong: jdk.internal.loader.ClassLoaders$AppClassLoader@73d16e93, change to: org.springframework.boot.loader.LaunchedURLClassLoader@14514713
dubbo
接口可以正常返回Java
对象,而不是HashMap
了resources
目录下新建文件META-INF/dubbo/org.apache.dubbo.common.serialize.hessian2.dubbo.Hessian2FactoryInitializer
default=xxxx.xxxxHessian2FactoryInitializer
@Slf4j
public class xxxxHessian2FactoryInitializer extends DefaultHessian2FactoryInitializer {
@Override
public SerializerFactory getSerializerFactory() {
Hessian2SerializerFactory hessian2SerializerFactory = new xxxxHessian2SerializerFactory();
hessian2SerializerFactory.getClassFactory().allow(RuntimeException.class.getName());
hessian2SerializerFactory.setAllowNonSerializable(Boolean.parseBoolean(System.getProperty("dubbo.hessian.allowNonSerializable", "false")));
return hessian2SerializerFactory;
}
}
Java
对象,是一个随机的状态,感觉启动的时候决定了这个hessian2
的类加载器Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。