JDK에서 객체를 반서열화하는 과정(ObjectInputStream#readObject)
8484 단어 readObject반서열화 대상
1. 자바 ObjectInputStream#readObject일 때 입력 흐름에서 대상을 읽고 대상 정보를 읽으며 읽는 과정에서 이상이 발생하면markDependency를 통해 처리한다.처리가 끝나면 등록된 콜백도 호출됩니다.
2. 대상을 읽는 과정, 먼저 대상을 읽은 다음java.io.ObjectInputStream.checkResolve(java.lang.Object);대상을 읽는 과정은 먼저 반서열화된 입력 흐름에서 대상의 표식을 읽는 것이다. 그 중에서 0x73은 Object이고 그 다음에java를 호출한다.io.ObjectInputStream.readOrdinaryObject(boolean) 읽기 대상입니다. 클래스 설명 정보인 ObjectStreamClass를 먼저 읽고 실례화합니다.
3. 메타데이터 정보를 읽는 과정:
java.io.ObjectInputStream.readClassDescriptor () 는 InputStream의 데이터를 읽고 ObjectStreamClass 정보를 해석합니다. 예를 들어name, uid, isProxy,hasWriteObjectData, externalizable, ObjectStreamFields입니다.그리고 나서
java.io.ObjectStreamClass.initNonProxy(java.io.ObjectStreamClass, java.lang.Class<?>, java.lang.ClassNotFoundException, java.io.ObjectStreamClass)
입력 흐름에서 해석된 ObjectStreamClass에 따라 새로운 ObjectStreamClass 대상을 구성합니다. 구조 방법에서 로컬 대상에 대한 설명 정보를 찾을 수 있습니다.이전에 이 두 ObjectStreamClass 묘사 대상은 모두 원격 대상의 정보이다. 즉, 모든 원격 대상 묘사 정보는 연결된 로컬 대상 묘사 정보가 있지만 그들은 모두 로컬 vm의 한 Class 대상을 가리킨다.로컬 대상 설명 정보 대상을 만들 때, 초유형 설명 정보 대상을 만들 것입니다.
Object StreamClass라는 실례에는 초유형 묘사 정보인 Object StreamClass, 구조 함수, 개인 write Object, 개인 read Object, 개인 read Object NoData 등 정보, write Replace,read Resolve 방법도 포함된다.
그 중에서 구조 방법을 얻을 때 현재 클래스의 [맨 윗부분에서serializable의 조상 클래스를 실현한 초클래스][즉 위에서 아래로 연속된 마지막 Serizable 인터페이스가 실현되지 않은 클래스]의 구조 함수를 얻고 반서열화된 클래스의 실례도 이 구조 함수를 통해 만들어졌다.eg, DTO는 BaseDTO를 계승하여 Serializable 인터페이스를 실현하고 반서열화할 때 BaseDTO의 구조 함수를 가져와 만든 실례입니다.BaseDTO가 Serializable 인터페이스를 동시에 실현하면 BaseDTO의 슈퍼클래스 구조 함수 (Object) 를 되돌려줍니다.
/**
* Returns subclass-accessible no-arg constructor of first non-serializable
* superclass, or null if none found. Access checks are disabled on the
* returned constructor (if any).
*/
private static Constructor<?> getSerializableConstructor(Class<?> cl) {
Class<?> initCl = cl;
//initCl , Serializable
while (Serializable.class.isAssignableFrom(initCl)) {
if ((initCl = initCl.getSuperclass()) == null) {
return null;
}
}
try {
Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null);
int mods = cons.getModifiers();
if ((mods & Modifier.PRIVATE) != 0 ||
((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
!packageEquals(cl, initCl)))
{
return null;
}
cons = reflFactory.newConstructorForSerialization(cl, cons);
cons.setAccessible(true);
return cons;
} catch (NoSuchMethodException ex) {
return null;
}
}
4. 실례화가 반서열화되고 있는 대상
ObjectStreamClass에서 만들어진 구조 방법cons를 호출하여 대상 실례를 만듭니다.앞에서 언급한 이 구조 방법cons는 현재 클래스[맨 윗부분에서serializable의 조상 클래스를 실현한 초클래스]의 구조 함수이다. 그러면 newInstance에서 나온 것은 현재 유형의 실례가 아니겠는가?이것은 자바에서 실현되었다.io.ObjectStreamClass.serializable Constructor(java.lang.Class)에서 현재 클래스 [최상위에서 Serializable의 조상 클래스를 실현한 초클래스]의 구조 함수를 획득한 후sun을 호출합니다.reflect.ReflectionFactory.새 Constructor Forserialization(java.lang.Class,java.lang.reflect.Constructor)에서 새로운 구조 함수 생성
public class sun.reflect.GeneratedSerializationConstructorAccessor1 extends sun.reflect.SerializationConstructorAccessorImpl {
// Method descriptor #26 ()V
// Stack: 1, Locals: 1
public GeneratedSerializationConstructorAccessor1();
0 aload_0 [this]
1 invokespecial sun.reflect.SerializationConstructorAccessorImpl() [36]
4 return
// Method descriptor #14 ([Ljava/lang/Object;)Ljava/lang/Object;
// Stack: 6, Locals: 2
public java.lang.Object newInstance(java.lang.Object[] arg0) throws java.lang.reflect.InvocationTargetException;
// DTO , DTO
0 new com.tmall.buy.serializable.DTO [6]
3 dup
4 aload_1 [arg0]
5 ifnull 24
8 aload_1 [arg0]
9 arraylength
10 sipush 0
13 if_icmpeq 24
16 new java.lang.IllegalArgumentException [22]
19 dup
20 invokespecial java.lang.IllegalArgumentException() [29]
23 athrow
// BaseDTO , DTO BaseDTO , super()
24 invokespecial com.tmall.buy.serializable.BaseDTO() [12]
27 areturn
28 invokespecial java.lang.Object.toString() : java.lang.String [42]
31 new java.lang.IllegalArgumentException [22]
34 dup_x1
35 swap
36 invokespecial java.lang.IllegalArgumentException(java.lang.String) [32]
39 athrow
40 new java.lang.reflect.InvocationTargetException [24]
43 dup_x1
44 swap
45 invokespecial java.lang.reflect.InvocationTargetException(java.lang.Throwable) [35]
48 athrow
Exception Table:
[pc: 0, pc: 24] -> 28 when : java.lang.ClassCastException
[pc: 0, pc: 24] -> 28 when : java.lang.NullPointerException
[pc: 24, pc: 27] -> 40 when : java.lang.Throwable
}
java를 호출합니다.lang.reflect.Constructor.newInstance(java.lang.Object[])
5, 반서열화 대상의 값을 읽는java.io.ObjectInputStream#readSerialData(java.lang.Object, java.io.ObjectStreamClass)
먼저 Object StreamClass의 계승 정보를 편평하게 하여Class DataSlot 수조로 만든다.만약 계승 시스템의 설명 정보가 입력 흐름에 관련 유형이 없다면hasData=false입니다.hasData==false의ClassDataSlot에 대해 이 slot 관련 ObjectStreamClass 관련 유형의readObjectNoData 방법을 호출합니다.
hasData=true & & 현재 반서열화된 클래스에readObject 방법이 있으면readObject 방법을 호출합니다.이렇게 하면 입력 흐름에서 반서열화된 대상의 필드 값을 읽을 수 없습니다. 자신의readObject 방법을 호출하고 입력 흐름의 값을 읽으려면readObject 방법에서java를 현시적으로 호출합니다.io.ObjectInputStream#defaultReadObject 방법만 있으면 됩니다. 이 방법도 변조된java입니다.io.ObjectInputStream.defaultReadFields(java.lang.Object, java.io.ObjectStreamClass).
그렇지 않으면hasData=true에서 java를 호출합니다.io.ObjectInputStream.defaultReadFields(java.lang.object,java.io.objectStreamClass) 방법은 실례 대상에 값을 부여합니다.
6. 반서열화할 때 값을 부여하는java.io.ObjectInputStream.defaultReadFields(java.lang.Object, java.io.ObjectStreamClass)
이 방법은 우선 대상 설명 정보 대상에 따라 정렬할 대상의 필드 정보를 읽습니다. ObjectStreamField. 이 필드는 원격 대상의 필드 값입니다. 로컬 대상의 필드 내용과 일치하지 않을 수도 있습니다. 입력 흐름에서 관련 세그먼트 값을 계속 읽습니다.마지막으로 Object StreamClass의Field Reflector라는 인용을 통해 최종적으로 반정렬될 대상에 값을 설정합니다.
7,4에서 선이 생성됩니다.reflect.GeneratedserializationConstructorAccessor1 클래스에서 하위 클래스 DTO 실례가 하이퍼클래스 BaseDTO 방법을 호출하는 데 왜 성공할 수 있습니까?방법 호출 명령은 5가지가 있는데 4에서BaseDTO 방법을 호출할 때 invokespecial 명령입니다. 이 명령은 invokevirtual과 달리 현재 대상의 실례에 따라 동적 분배되지 않습니다.따라서BaseDTO#
* invokevirtual invokes an instance method of an object, dispatching on the (virtual) type of the object. This is the normal method dispatch in the Java programming language.
* invokeinterface invokes an interface method, searching the methods implemented by the particular run-time object to find the appropriate method.
* invokespecial invokes an instance method requiring special handling,whether an instance initialization method (§2.9), a private method, or a superclass method.
* invokestatic invokes a class (static) method in a named class.
* invokedynamic invokes the method which is the target of the call site object bound to the invokedynamic instruction. The call site object was bound to a specific lexical occurrence of the invokedynamic instruction by the Java Virtual Machine as a result of running a bootstrap method before the first execution of the instruction. Therefore, each occurrence of an invokedynamic instruction has a unique linkage state, unlike the other instructions which invoke methods.
8、이 시점에 Hessian2는 어떻게 했을까요?com.caucho.hessian.io.UnsafeDeserializer.instantiate()
protected Object instantiate() throws Exception{
return _unsafe.allocateInstance(_type);
}
그리고unsafe.allocateInstance 메서드의 기능은 다음과 같습니다.
Allocate an instance but do not run any constructor. Initializes the class if it has not yet been.