原文链接:Java 序列化 writeObject分析
接着上一篇Java readObject分析,这一篇我们来看一下writeObject知识点先来了解几个序列化中常见的属性 serialVersionUID也叫suid ,基于类的属性方法等参数会生成一个默认的suid,用来验证类是否发生变化,在readObject分析中讲到,会检查suid,如果发生变化,那么是不能反序列化的。 transient 修饰符在之前提到序列化的条件中讲到过,实现java.io.Serializable的接口,才可被反序列化,并且所有属性都是可序列化的,而这里并不包括被trainsient修饰符修饰的属性,该属性是不参数序列化和反序列化的 static 关键字序列化仅对特定的变量产生作用,但 static 修饰的变量并不特定于任何对象。因此,静态变量不会参与序列化。 writeObject 分析例子 :Java 反序列化-开篇中第一个代码 import java.io.*;
public class test{
public static void main(String args[]) throws Exception{
//定义myObj对象
MyObject myObj = new MyObject();
myObj.name = "hi";
//创建一个包含对象进行反序列化信息的”object”数据文件
FileOutputStream fos = new FileOutputStream("object");
ObjectOutputStream os = new ObjectOutputStream(fos);
//writeObject()方法将myObj对象写入object文件
os.writeObject(myObj);
os.close();
//从文件中反序列化obj对象
FileInputStream fis = new FileInputStream("object");
ObjectInputStream ois = new ObjectInputStream(fis);
//恢复对象
MyObject objectFromDisk = (MyObject)ois.readObject();
System.out.println(objectFromDisk.name);
ois.close();
}
}
class MyObject implements Serializable {
public String name;
//重写readObject()方法
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//执行默认的readObject()方法
in.defaultReadObject();
//执行打开计算器程序命令
Runtime.getRuntime().exec("open -a Calculator");
}
}在调用writeObject()进行序列化之前会调用ObjectOutputStream的构造函数,new 一个ObjectOutputStream对象 public ObjectOutputStream(OutputStream out) throws IOException {
verifySubclass();
bout = new BlockDataOutputStream(out);
handles = new HandleTable(10, (float) 3.00);
subs = new ReplaceTable(10, (float) 3.00);
enableOverride = false;
writeStreamHeader();
bout.setBlockDataMode(true);
if (extendedDebugInfo) {
debugInfoStack = new DebugTraceInfoStack();
} else {
debugInfoStack = null;
}
}boot是底层的字节数据容器,接着实现writeStreamHeader()方法 protected void writeStreamHeader() throws IOException {
bout.writeShort(STREAM_MAGIC);
bout.writeShort(STREAM_VERSION);
}写入文件头,魔数和版本 final static short STREAM_MAGIC = (short)0xaced;
/**
* Version number that is written to the stream header.
*/
final static short STREAM_VERSION = 5;这个也是序列化文件的特征之一。 从ObjectOutputStream.writeObject 跟进代码 public final void writeObject(Object obj) throws IOException {
if (enableOverride) {
writeObjectOverride(obj);
return;
}
try {
writeObject0(obj, false);
} catch (IOException ex) {
if (depth == 0) {
writeFatalException(ex);
}
throw ex;
}
}这里的enableOverride在新建ObjectOutputStream对象时实例化,如果为true,则调用writeObjectOverride()而不是writeObject() writeObject0(obj, false); 跟进去 private void writeObject0(Object obj, boolean unshared)
throws IOException
{
...
try {
// handle previously written and non-replaceable objects
...
// check for replacement object
Object orig = obj;
Class<?> cl = obj.getClass();
ObjectStreamClass desc;
for (;;) {
// REMIND: skip this check for strings/arrays?
Class<?> repCl;
desc = ObjectStreamClass.lookup(cl, true);
if (!desc.hasWriteReplaceMethod() ||
(obj = desc.invokeWriteReplace(obj)) == null ||
(repCl = obj.getClass()) == cl)
{
break;
}
cl = repCl;
}
...
// if object replaced, run through original checks a second time
...
// remaining cases
if (obj instanceof String) {
writeString((String) obj, unshared);
} else if (cl.isArray()) {
writeArray(obj, desc, unshared);
} else if (obj instanceof Enum) {
writeEnum((Enum<?>) obj, desc, unshared);
} else if (obj instanceof Serializable) {
writeOrdinaryObject(obj, desc, unshared);
} else {
if (extendedDebugInfo) {
throw new NotSerializableException(
cl.getName() + "\n" + debugInfoStack.toString());
} else {
throw new NotSerializableException(cl.getName());
}
}
} finally {
depth--;
bout.setBlockDataMode(oldMode);
}
}生成一个描述序列化对象的类元信息 的ObjectStreamClass对象,根据code 看出,obj如果是String,Array,Enum 直接调用默认方法进行序列化,如果实现了Serializable,则会调用writeOrdinaryObject private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
if (extendedDebugInfo) {
debugInfoStack.push(
(depth == 1 ? "root " : "") + "object (class \"" +
obj.getClass().getName() + "\", " + obj.toString() + ")");
}
try {
desc.checkSerialize();
bout.writeByte(TC_OBJECT);
writeClassDesc(desc, false);
handles.assign(unshared ? null : obj);
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc);
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}bout在ObjectOutputStream新建时已经提到 ,这是个底层字节数据容器,在代码中先写入了TC_OBJECT,表示这是一个新的Object 也就是在文件格式提到的0x73 final static byte TC_OBJECT = (byte)0x73;跟进writeClassDesc private void writeClassDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
int handle;
if (desc == null) {
writeNull();
} else if (!unshared && (handle = handles.lookup(desc)) != -1) {
writeHandle(handle);
} else if (desc.isProxy()) {
writeProxyDesc(desc, unshared);
} else {
writeNonProxyDesc(desc, unshared);
}
}将类描述符以流的方式写入,这里有几种方法:动态代理,普通方式。先检测传入的类描述符是否为null 不为空,调用writeNonProxyDesc() private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_CLASSDESC);
handles.assign(unshared ? null : desc);
if (protocol == PROTOCOL_VERSION_1) {
// do not invoke class descriptor write hook with old protocol
desc.writeNonProxy(this);
} else {
writeClassDescriptor(desc);
}
Class<?> cl = desc.forClass();
bout.setBlockDataMode(true);
if (cl != null && isCustomSubclass()) {
ReflectUtil.checkPackageAccess(cl);
}
annotateClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
writeClassDesc(desc.getSuperDesc(), false);
}首先写入一个字节的TC_CLASSDESC,表示这额是一个新的class 描述符,接着调用writeNonProxy void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);
out.writeLong(getSerialVersionUID());
byte flags = 0;
if (externalizable) {
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
int protocol = out.getProtocolVersion();
if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
flags |= ObjectStreamConstants.SC_BLOCK_DATA;
}
} else if (serializable) {
flags |= ObjectStreamConstants.SC_SERIALIZABLE;
}
if (hasWriteObjectData) {
flags |= ObjectStreamConstants.SC_WRITE_METHOD;
}
if (isEnum) {
flags |= ObjectStreamConstants.SC_ENUM;
}
out.writeByte(flags);
out.writeShort(fields.length);
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields;
out.writeByte(f.getTypeCode());
out.writeUTF(f.getName());
if (!f.isPrimitive()) {
out.writeTypeString(f.getTypeString());
}
}
}将类元信息写入,如:类名 name , 序列号版本 suid,类的标识 flags 我们 跟进out.writeUTF(name);看看如何写入name的所属信息的 void writeUTF(String s, long utflen) throws IOException {
if (utflen > 0xFFFFL) {
throw new UTFDataFormatException();
}
writeShort((int) utflen);
if (utflen == (long) s.length()) {
writeBytes(s);
} else {
writeUTFBody(s);
}
}调用writeUTF()方法写入对象所属类名,以UTF格式写入给定的属性, 回到上层代码,继续看,SUID的生成方式,跟进getSerialVersionUID public long getSerialVersionUID() {
// REMIND: synchronize instead of relying on volatile?
if (suid == null) {
suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
return computeDefaultSUID(cl);
}
}
);
}
return suid.longValue();
}若suid为空,就进入computeDefaultSUID(cl) 计算 会创建对象DataOutputStream将信息写入 private static long computeDefaultSUID(Class<?> cl) {
if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
{
return 0L;
}
try {
//创建DataOutputStream 将信息写入ByteArrayOutputStream中
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
// 写入类名
dout.writeUTF(cl.getName());
// 写入 modifier
int classMods = cl.getModifiers() &
(Modifier.PUBLIC | Modifier.FINAL |
Modifier.INTERFACE | Modifier.ABSTRACT);
/*
* compensate for javac bug in which ABSTRACT bit was set for an
* interface only if the interface declared methods
*/
Method[] methods = cl.getDeclaredMethods();
if ((classMods & Modifier.INTERFACE) != 0) {
classMods = (methods.length > 0) ?
(classMods | Modifier.ABSTRACT) :
(classMods & ~Modifier.ABSTRACT);
}
dout.writeInt(classMods);
// 按照interface name 排序写入
if (!cl.isArray()) {
/*
* compensate for change in 1.2FCS in which
* Class.getInterfaces() was modified to return Cloneable and
* Serializable for array classes.
*/
Class<?>[] interfaces = cl.getInterfaces();
String[] ifaceNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
ifaceNames = interfaces.getName();
}
Arrays.sort(ifaceNames);
for (int i = 0; i < ifaceNames.length; i++) {
dout.writeUTF(ifaceNames);
}
}
根据field拍下,把name,modifier,signature写入
Field[] fields = cl.getDeclaredFields();
MemberSignature[] fieldSigs = new MemberSignature[fields.length];
for (int i = 0; i < fields.length; i++) {
fieldSigs = new MemberSignature(fields);
}
Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
return ms1.name.compareTo(ms2.name);
}
});
// 当modifier为 privite,static transient 就不写入,
for (int i = 0; i < fieldSigs.length; i++) {
MemberSignature sig = fieldSigs;
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
Modifier.TRANSIENT);
if (((mods & Modifier.PRIVATE) == 0) ||
((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
{
dout.writeUTF(sig.name);
dout.writeInt(mods);
dout.writeUTF(sig.signature);
}
}
//这里判断存在staticInitializer
if (hasStaticInitializer(cl)) {
dout.writeUTF("<clinit>");
dout.writeInt(Modifier.STATIC);
dout.writeUTF("()V");
}
//根据signature排序,然后将非private的构造函数写入
Constructor<?>[] cons = cl.getDeclaredConstructors();
MemberSignature[] consSigs = new MemberSignature[cons.length];
for (int i = 0; i < cons.length; i++) {
consSigs = new MemberSignature(cons);
}
Arrays.sort(consSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
return ms1.signature.compareTo(ms2.signature);
}
});
for (int i = 0; i < consSigs.length; i++) {
MemberSignature sig = consSigs;
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL |
Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.ABSTRACT | Modifier.STRICT);
if ((mods & Modifier.PRIVATE) == 0) {
dout.writeUTF("<init>");
dout.writeInt(mods);
dout.writeUTF(sig.signature.replace('/', '.'));
}
}
// 同样,method name 和signature 排序后,写入非private method的那name,modifier,signature
MemberSignature[] methSigs = new MemberSignature[methods.length];
for (int i = 0; i < methods.length; i++) {
methSigs = new MemberSignature(methods);
}
Arrays.sort(methSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
int comp = ms1.name.compareTo(ms2.name);
if (comp == 0) {
comp = ms1.signature.compareTo(ms2.signature);
}
return comp;
}
});
for (int i = 0; i < methSigs.length; i++) {
MemberSignature sig = methSigs;
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL |
Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.ABSTRACT | Modifier.STRICT);
if ((mods & Modifier.PRIVATE) == 0) {
dout.writeUTF(sig.name);
dout.writeInt(mods);
dout.writeUTF(sig.signature.replace('/', '.'));
}
}
dout.flush();
// 最后把bout 做SHA 加密,取前8个byte 作为suid
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] hashBytes = md.digest(bout.toByteArray());
long hash = 0;
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
hash = (hash << 8) | (hashBytes & 0xFF);
}
return hash;
} catch (IOException ex) {
throw new InternalError(ex);
} catch (NoSuchAlgorithmException ex) {
throw new SecurityException(ex.getMessage());
}
}返回suid 通过writeLong方法写入 接下来,通过flags 来判断当前对象所属 flag bit
SC_EXTERNALIZABLE0x04
SC_SERIALIZABLE0x02
SC_WRITE_METHOD0x01
SC_ENUM0x10本例子中,flags = 0x02 for循环中,一次写入序列化对象的字段个数,字段的元数据, TypeCode Java Type
Bbyte
Cchar
Ddouble
Ffloat
Iint
Jlong
Lclass or interface
Sshort
Zboolean
[array最后代码走进if判断 writeTypeString(f.getTypeString()) void writeTypeString(String str) throws IOException {
int handle;
if (str == null) {
writeNull();
} else if ((handle = handles.lookup(str)) != -1) {
writeHandle(handle);
} else {
writeString(str, false);
}
}调用writeTypeString()方法写入代表对象或者类型字符串,最后调用writeString private void writeString(String str, boolean unshared) throws IOException {
handles.assign(unshared ? null : str);
long utflen = bout.getUTFLength(str);
if (utflen <= 0xFFFF) {
bout.writeByte(TC_STRING);
bout.writeUTF(str, utflen);
} else {
bout.writeByte(TC_LONGSTRING);
bout.writeLongUTF(str, utflen);
}
}写入标志位TC_String,表示接下来的数据是字符串,然后通过writeUTF写入字符串 返回上层代码 private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
...
Class<?> cl = desc.forClass();
bout.setBlockDataMode(true);
if (cl != null && isCustomSubclass()) {
ReflectUtil.checkPackageAccess(cl);
}
annotateClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
writeClassDesc(desc.getSuperDesc(), false);
}接下来写入TC_ENDBLOCKDATA 表示对一个object的描述块结束 然后调用writeClassDesc()方法调用上层代码,形成递归调用,每次写入父类描述,直到没有父类可以被返回,也就是 传入的ObjectStreamClass对象为null时,会写入一个字节的标识位TC_NULL 回到writeOrdinaryObject()方法 private void writeOrdinaryObject(Object obj,
ObjectStreamClass desc,
boolean unshared)
throws IOException
{
...
try {
desc.checkSerialize();
...
if (desc.isExternalizable() && !desc.isProxy()) {
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc); // 写入序列化对象的实例数据
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}writeOrdinaryObject()方法,先写入子类的类元数据,然后在递归调用写入父类的类元数据。 接下来进入writeSerialData()方法,写入被序列化的对象 private void writeSerialData(Object obj, ObjectStreamClass desc)
throws IOException
{
ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots.desc;
if (slotDesc.hasWriteObjectMethod()) {
try{
...
slotDesc.invokeWriteObject(obj, this);
...
}
} else {
defaultWriteFields(obj, slotDesc);//调用默认的方法写入实例数据
}
}
}对于没有自定义writeObject()方法,会调用defaultwriteFields()方法写入数据, private void defaultWriteFields(Object obj, ObjectStreamClass desc)
throws IOException
{
Class<?> cl = desc.forClass();
if (cl != null && obj != null && !cl.isInstance(obj)) {
throw new ClassCastException();
}
desc.checkDefaultSerialize();
int primDataSize = desc.getPrimDataSize();
if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
}
// 获取对应类中的基本数据类型的数据,并保存在primVals
desc.getPrimFieldValues(obj, primVals);
bout.write(primVals, 0, primDataSize, false);
// 获取对应类的所有字段对象
ObjectStreamField[] fields = desc.getFields(false);
Object[] objVals = new Object[desc.getNumObjFields()];
int numPrimFields = fields.length - objVals.length;
desc.getObjFieldValues(obj, objVals);
for (int i = 0; i < objVals.length; i++) {
if (extendedDebugInfo) {
debugInfoStack.push(
"field (class \"" + desc.getName() + "\", name: \"" +
fields[numPrimFields + i].getName() + "\", type: \"" +
fields[numPrimFields + i].getType() + "\")");
}
try {
// 对所有Object类型的字段递归调用writeObject0()方法写入对应的数据
writeObject0(objVals,
fields[numPrimFields + i].isUnshared());
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}这个方法,获取了对应类的基本类型的字段数据,写入底层的字节容器bout,获取对应类型的字段成员,递归writeObject0()写入对应的数据。
writeObject 方法图
|