关于Dubbo默认序列化Hessian的问题

夫子与歌 2016-08-23

项目中使用了服务框架Dubbo进行远程调用,框架持久层使用的是Spring data jpa,一同事开发的Dubbo接口类似入如下: 

XXXXService.findBy(PageRequest pg );其中PageRequest 是spring data jps提供的分页排序实现类。 

当在客户端调用该接口时,PageRequest 中明明传入的油蚕丝,但一到Dubbo反序列化,Dubbo 

总时抛  PageRequest  could not be instantiated;跟了下Dubbo的源码,发现这个异常是在 

JavaDeserializer(Dubbo序列化类)中抛出的,再看异常cause by,发现是 PageRequest的 

父类AbstractPageRequest 构造函数检查失败出的问题, 
public AbstractPageRequest(int page, int size) { 

if (page < 0) { 
throw new IllegalArgumentException("Page index must not be less than zero!"); 


if (size < 1) { 
throw new IllegalArgumentException("Page size must not be less than one!"); 


this.page = page; 
this.size = size; 

就红的地方抛出类异常,也就是说size=0啦。很奇怪,明明出入的PageRequest有值,为啥Dubbo反序列就把变成零了,带着这个问题,有跟了一遍Dubbo源码,发现在JavaDeserializer 
public JavaDeserializer(Class cl) 
  { 
    _type = cl; 
    _fieldMap = getFieldMap(cl); 

    _readResolve = getReadResolve(cl); 

    if (_readResolve != null) { 
      _readResolve.setAccessible(true); 
    } 

    Constructor []constructors = cl.getDeclaredConstructors(); 
    long bestCost = Long.MAX_VALUE; 

    for (int i = 0; i < constructors.length; i++) { 
      Class []param = constructors[i].getParameterTypes(); 
      long cost = 0; 

      for (int j = 0; j < param.length; j++) { 
cost = 4 * cost; 

if (Object.class.equals(param[j])) 
  cost += 1; 
else if (String.class.equals(param[j])) 
  cost += 2; 
else if (int.class.equals(param[j])) 
  cost += 3; 
else if (long.class.equals(param[j])) 
  cost += 4; 
else if (param[j].isPrimitive()) 
  cost += 5; 
else 
  cost += 6; 
      } 

      if (cost < 0 || cost > (1 << 48)) 
cost = 1 << 48; 

      cost += (long) param.length << 48; 

      if (cost < bestCost) { 
        _constructor = constructors[i]; 
        bestCost = cost; 
      } 
    } 

    if (_constructor != null) { 
      _constructor.setAccessible(true); 
      Class []params = _constructor.getParameterTypes(); 
      _constructorArgs = new Object[params.length]; 
      for (int i = 0; i < params.length; i++) { 
        _constructorArgs[i] = getParamArg(params[i]); 
      } 
    } 
  } 
有对_constructor和 _constructorArgs初始化的过程,大致意思是会调用所有构造函数中参数最少的那个。 
也就是会调用PageRequest中 
public PageRequest(int page, int size) { 
this(page, size, null); 


再跟到上面标红的地方,也就是_constructorArgs初始化代码 
protected static Object getParamArg(Class cl) 
  { 
    if (! cl.isPrimitive()) 
      return null; 
    else if (boolean.class.equals(cl)) 
      return Boolean.FALSE; 
    else if (byte.class.equals(cl)) 
      return new Byte((byte) 0); 
    else if (short.class.equals(cl)) 
      return new Short((short) 0); 
    else if (char.class.equals(cl)) 
      return new Character((char) 0); 
   else if (int.class.equals(cl)) 
      return Integer.valueOf(0); 
    else if (long.class.equals(cl)) 
      return Long.valueOf(0); 
    else if (float.class.equals(cl)) 
      return Float.valueOf(0); 
    else if (double.class.equals(cl)) 
      return Double.valueOf(0); 
    else 
      throw new UnsupportedOperationException(); 
  } 
上面方法加红的部分,答案揭晓,dubbo全返回0了,所有才有了前面的错误Page size must not be less than one!
总结,Dubbo默认使用的是Hessian序列化,具体可以看下Hessian这个序列化框架,若使用Hessian,默认情况下最好都提供一个无参构造函数 

相关推荐

ganyouxianjava / 0评论 2012-05-31