您的位置:首页 > 编程语言 > Java开发

java的序列化机制原理分析

2012-06-02 08:49 946 查看
我们查看下ObjectOutputStream的writeObject方法

//final方法,不允许子类覆盖
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;
}
}


如果要自定义这个序列化过程,则可以写一个子类,集成ObjectOutputStream,然后覆盖其两个方法

protected ObjectOutputStream() throws IOException, SecurityException {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
}
bout = null;
handles = null;
subs = null;
enableOverride = true;
debugInfoStack = null;
}
protected void writeObjectOverride(Object obj) throws IOException {
}


我们再看下具体的writeObject0方法:

private void writeObject0(Object obj, boolean unshared)
throws IOException
{
boolean oldMode = bout.setBlockDataMode(false);
depth++;
try {
// 先对obj实例的类信息进行序列化,
int h;
if ((obj = subs.lookup(obj)) == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {//可以自定义class类信息的序列化handler
writeHandle(h);
return;
} else if (obj instanceof Class) { //类信息序列化
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) { //类信息序列化,此时还包括serialVersionUID
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}

// 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 (enableReplace) {
Object rep = replaceObject(obj);
if (rep != obj && rep != null) {
cl = rep.getClass();
desc = ObjectStreamClass.lookup(cl, true);
}
obj = rep;
}

// if object replaced, run through original checks a second time
//如果类信息被替换过,则需要进行第二次处理
if (obj != orig) {
subs.assign(orig, obj);
if (obj == null) {
writeNull();
return;
} else if (!unshared && (h = handles.lookup(obj)) != -1) {
writeHandle(h);
return;
} else if (obj instanceof Class) {
writeClass((Class) obj, unshared);
return;
} else if (obj instanceof ObjectStreamClass) {
writeClassDesc((ObjectStreamClass) obj, unshared);
return;
}
}

// 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) { //我们的bean需要实现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);
}
}


我们先简单的看下如果是一个String,如何做这个序列化的过程:

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);
}
}


bout的writeUTF方法:

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);
}
}


很简单,就是写入一个字符串的一个字节的标示符,然后写入字符串的字节流。

那么再看看writeOrdinaryObject(obj, desc, unshared);如何对一个bean进行序列化

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(); //检查下是否可以进行序列化,比如socket对象之类的,如果对象无法进行序列化,则抛出异常。

bout.writeByte(TC_OBJECT); //先写入一个字节的类对象的标示符
writeClassDesc(desc, false); //序列化对象的class类信息
handles.assign(unshared ? null : obj); //保存类的seariableID跟对象的映射关系
if (desc.isExternalizable() && !desc.isProxy()) { //如果我们自定义了对象的序列化过程,则调用对象的writeExternalData方法。如果实现Externalizable
//    /** true if represented class implements Externalizable */
// private boolean externalizable;
writeExternalData((Externalizable) obj);
} else {
writeSerialData(obj, desc); //否则调用默认的序列化方法
}
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}


然后我们先看看writeClassDesc(desc, false)的实现:

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()) { //如果是proxy对象,则调用该序列化机制 ,isProxy的判断
//isProxy = Proxy.isProxyClass(cl); Returns true if and only if the specified class was dynamically generated to be a proxy class using the getProxyClass method or the newProxyInstance method.
writeProxyDesc(desc, unshared);
} else {
writeNonProxyDesc(desc, unshared);
}
}

/**
* Writes class descriptor representing a dynamic proxy class to stream.
*/
private void writeProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_PROXYCLASSDESC); //写入代理对象的标示符
handles.assign(unshared ? null : desc);

Class cl = desc.forClass();
Class[] ifaces = cl.getInterfaces(); //如果是proxy对象,则写入对象的interfaces的名称
bout.writeInt(ifaces.length); //先写入interface个数
for (int i = 0; i < ifaces.length; i++) {
bout.writeUTF(ifaces[i].getName()); //再写入每个interface的名称
}

bout.setBlockDataMode(true);
annotateProxyClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA); //结束标签

writeClassDesc(desc.getSuperDesc(), false);//递归写入父类的序列化信息,因为java是单继承,
}

/**
* Writes class descriptor representing a standard (i.e., not a dynamic
* proxy) class to stream.
*/
private void writeNonProxyDesc(ObjectStreamClass desc, boolean unshared)
throws IOException
{
bout.writeByte(TC_CLASSDESC);//写入class对象的标示符
handles.assign(unshared ? null : desc);

if (protocol == PROTOCOL_VERSION_1) { //如果非代理类对象的具体class信息,查看下面的方法
// do not invoke class descriptor write hook with old protocol
desc.writeNonProxy(this);
} else {
writeClassDescriptor(desc);
}

Class cl = desc.forClass();
bout.setBlockDataMode(true);
annotateClass(cl);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);

writeClassDesc(desc.getSuperDesc(), false);//递归写入父类的序列化信息,因为java是单继承,
}


writeClassDescriptor(desc)方法:

throws IOException
{
desc.writeNonProxy(this);
}

void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);//写入类的名称
out.writeLong(getSerialVersionUID());//写入类的SerialVersionUID

byte flags = 0;
if (externalizable) {//是否实现externalizable接口
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
int protocol = out.getProtocolVersion();
if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
flags |= ObjectStreamConstants.SC_BLOCK_DATA;
}
} else if (serializable) {//是否实现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); //遍历写入各个类的各个field字段类型名称等信息
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
out.writeByte(f.getTypeCode()); //typecode参考ObjectStreamField.java类
out.writeUTF(f.getName());
if (!f.isPrimitive()) {
out.writeTypeString(f.getTypeString());
}
}
}


typecode:

case 'Z': type = Boolean.TYPE; break;
case 'B': type = Byte.TYPE; break;
case 'C': type = Character.TYPE; break;
case 'S': type = Short.TYPE; break;
case 'I': type = Integer.TYPE; break;
case 'J': type = Long.TYPE; break;
case 'F': type = Float.TYPE; break;
case 'D': type = Double.TYPE; break;
case 'L':
case '[': type = Object.class; break;


至此,对象obj的class相关信息已经全部写入。

然后我们再查看具体写入obj数据的过程

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[i].desc;
if (slotDesc.hasWriteObjectMethod()) { //Returns true if represented class is serializable (but not externalizable) and defines a conformant writeObject method. Otherwise, returns false.
Object oldObj = curObj;
ObjectStreamClass oldDesc = curDesc;
PutFieldImpl oldPut = curPut;
curObj = obj;
curDesc = slotDesc;
curPut = null;

if (extendedDebugInfo) {
debugInfoStack.push(
"custom writeObject data (class \"" +
slotDesc.getName() + "\")");
}
try {
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}

curObj = oldObj;
curDesc = oldDesc;
curPut = oldPut;
} else {
defaultWriteFields(obj, slotDesc); //写入对象的字段数据
}
}
}
private void defaultWriteFields(Object obj, ObjectStreamClass desc)
throws IOException
{
// REMIND: perform conservative isInstance check here?
desc.checkDefaultSerialize();

int primDataSize = desc.getPrimDataSize(); //先写入private field的数据
if (primVals == null || primVals.length < primDataSize) {
primVals = new byte[primDataSize];
}
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++) { //写入非private的数据
if (extendedDebugInfo) {
debugInfoStack.push(
"field (class \"" + desc.getName() + "\", name: \"" +
fields[numPrimFields + i].getName() + "\", type: \"" +
fields[numPrimFields + i].getType() + "\")");
}
try {
writeObject0(objVals[i],
fields[numPrimFields + i].isUnshared()); //递归调用writeObject0写入每个field的数据
} finally {
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
}
}


当然ObjectInputStream也类似。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: