hessian 서열화 버그

5073 단어 hessian
최근 프로젝트에서 ProductDraftDO 대상을 원격 서비스로 전송하는 이상한 문제가 발견되었습니다. 원격 서비스에서 얻은 ProductDraftDO 대상의ActionTrace는null입니다.전송하기 전에 분명히 값이 있었어.ActionTrace 클래스는 모든 속성을 정렬할 수 있는 서열화된 인터페이스를 실현했습니다.마지막으로 원인을 규명한 것은 서열화된 문제였다.프로젝트 중의 원격 서비스는 dubbo로 이루어지기 때문에 Hessian은 dubbo의 기본 서열화 프로토콜로 자바의 서열화 성능보다 훨씬 높다.hessian이 대상을 서열화할 때 기본 서열화 클래스는com입니다.caucho.hessian.io. JavaSerializer. JavaSerializer의 writeObject 메소드 코드 세그먼트는 다음과 같습니다.
    try {
      out.writeMapBegin(cl.getName());
      for (int i = 0; i < _fields.length; i++) {
        Field field = _fields[i];
        out.writeString(field.getName());
        out.writeObject(field.get(obj));
      }
      out.writeMapEnd();
    } catch (IllegalAccessException e) {
      throw new IOException(String.valueOf(e));
}
 
속성과 속성 값을 모두 흐름에 기록합니다. 여기는 아무런 문제가 없는 것 같지만, 이 Field들은 어떻게 생겼습니까?JavaSerializer의 구조 함수를 보십시오.
public JavaSerializer(Class cl) {
        _writeReplace = getWriteReplace(cl);
        if (_writeReplace != null) _writeReplace.setAccessible(true);

        ArrayList primitiveFields = new ArrayList();
        ArrayList compoundFields = new ArrayList();
        for (; cl != null; cl = cl.getSuperclass()) {
            Field[] fields = cl.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) continue;

                // XXX: could parameterize the handler to only deal with public
                field.setAccessible(true);

                if (field.getType().isPrimitive() || field.getType().getName().startsWith("java.lang.")
                    && !field.getType().equals(Object.class)) primitiveFields.add(field);
                else compoundFields.add(field);
            }
        }

        ArrayList fields = new ArrayList();
        fields.addAll(primitiveFields);
        fields.addAll(compoundFields);

        _fields = new Field[fields.size()];
        fields.toArray(_fields);
    }
 
현재class의 모든 필드를 가져오고 부모 클래스의 모든 필드를 가져옵니다.서열화할 때 모든 필드를 Array List에 놓고 이진 흐름에 순서대로 쓴다. 반서열화할 때 모든 필드는 하나의HashMap에 넣고HashMap의 키는 중복될 수 없다. 비극이 발생한다. 하위 클래스와 하위 클래스가 같은 이름이 있는 필드가 있으면 문제가 생기고 하위 클래스의 값은 하위 클래스의 값을 덮어쓴다.JavaDeserializer의 getFieldMap 방법을 보십시오. 부모 필드는 하위 필드를 덮어씁니다.
/**
   * Creates a map of the classes fields.
   */
  protected HashMap getFieldMap(Class cl)
  {
    HashMap fieldMap = new HashMap();
   
    for (; cl != null; cl = cl.getSuperclass()) {
      Field []fields = cl.getDeclaredFields();
      for (int i = 0; i < fields.length; i++) {
        Field field = fields[i];

        if (Modifier.isTransient(field.getModifiers()) ||
            Modifier.isStatic(field.getModifiers()))
          continue;
        else if (fieldMap.get(field.getName()) != null)
          continue;

        // XXX: could parameterize the handler to only deal with public
        try {
          field.setAccessible(true);
        } catch (Throwable e) {
          e.printStackTrace();
        }

        fieldMap.put(field.getName(), field);
      }
    }

    return fieldMap;
  }
 
그리고 필드에 따라 값을 받아서 자바 Deserializer의readMap 방법의 코드 세션을 보십시오
  while (!in.isEnd()) {
            Object key = in.readObject();
            Field field = (Field) _fieldMap.get(key);
            if (field != null) {
                Object value = in.readObject(field.getType());
                try {
                    field.set(obj, value);
                } catch (Throwable e) {
                    IOException e1 = new IOException("Failed setting: " + field + " with " + value + "
" + e.toString()); e1.initCause(e); throw e1; } } else { Object value = in.readObject(); } }
 
이진 데이터를 보낼 때, 하위 클래스 데이터는 앞에 있고, 부 클래스 데이터는 뒤에 있다.이진 데이터를 수신할 때, 하위 클래스 데이터는 앞에 있고, 부 클래스 데이터는 뒤에 있다.따라서 같은 이름의 필드에 대해 하위 클래스의 이 필드 값은 두 번 부여되고 항상 상위 클래스의 값에 덮어쓰여 하위 클래스의 필드 값을 잃어버린다.분석이 끝난 다음에 다시 돌아보면 ProductDraftDO에는 ActionTrace 유형 필드인 actionTrace가 있고 부류 ProductDO에도 ActionTrace 유형 필드인 actionTrace가 있다.반서열화할 때 ProductDraftDO의 actionTrace는 ProductDO의 actionTrace에 덮여 있기 때문에 ProductDraftDO의 actionTrace는 항상 비어 있습니다.왜 부류와 자류에 모두 ActionTrace가 있는지에 대해서는 역사적 원인이므로 여기서 토론하지 않는다.따라서hessian 서열화를 사용할 때 하위 클래스와 부모 클래스는 같은 이름의 필드가 있을 수 없다는 것을 반드시 주의해야 한다.dubbo를 사용할 때 정렬화 프로토콜이 지정되지 않으면 이 문제도 주의해야 합니다.

좋은 웹페이지 즐겨찾기