Hadoop的ObjectWritable保存了一个可以在Hadoop RPC里面传输的对象和对象类型的说明信息。用于客户端与服务器间传输的Writable对象,也是对RPC传输对象的封装,因为RPC上交换的信息只能是JAVA的基础数据类型,String或者Writable类型,而ObjectWritable是对其子类的抽象封装,该类大致情况如下:
ObjectWritable会往流里写入如下信息:
对象类名,对象自己的串行化结果
其序列化和反序列化方法如下:
public void readFields(DataInput in) throws IOException {
readObject(in, this, this.conf);
}
public void write(DataOutput out) throws IOException {
writeObject(out, instance, declaredClass, conf);
}
分别调用的是writeObject(out, instance, declaredClass, conf)和readObject(in, this, this.conf)方法:
writeObject(out, instance, declaredClass, conf)方法:该方法逐一分析待xulie的数据类型并且实现序列化。
public static void writeObject(DataOutput out, Object instance,
Class declaredClass,
Configuration conf) throws IOException {
//对象为空则抽象出内嵌数据类型NullInstance
if (instance == null) { // null
instance = new NullInstance(declaredClass, conf);
declaredClass = Writable.class;
}
//先写入类名
UTF8.writeString(out, declaredClass.getName()); // always write declared
/*
* 封装的对象为数组类型,则逐个序列化(序列化为length+对象的序列化内容)
* 采用了迭代
*/
if (declaredClass.isArray()) { // array
int length = Array.getLength(instance);
out.writeInt(length);
for (int i = 0; i < length; i++) {
writeObject(out, Array.get(instance, i),
declaredClass.getComponentType(), conf);
}
//为String类型直接写入
} else if (declaredClass == String.class) { // String
UTF8.writeString(out, (String)instance);
}//基本数据类型写入
else if (declaredClass.isPrimitive()) { // primitive type
if (declaredClass == Boolean.TYPE) { // boolean
out.writeBoolean(((Boolean)instance).booleanValue());
} else if (declaredClass == Character.TYPE) { // char
out.writeChar(((Character)instance).charValue());
} else if (declaredClass == Byte.TYPE) { // byte
out.writeByte(((Byte)instance).byteValue());
} else if (declaredClass == Short.TYPE) { // short
out.writeShort(((Short)instance).shortValue());
} else if (declaredClass == Integer.TYPE) { // int
out.writeInt(((Integer)instance).intValue());
} else if (declaredClass == Long.TYPE) { // long
out.writeLong(((Long)instance).longValue());
} else if (declaredClass == Float.TYPE) { // float
out.writeFloat(((Float)instance).floatValue());
} else if (declaredClass == Double.TYPE) { // double
out.writeDouble(((Double)instance).doubleValue());
} else if (declaredClass == Void.TYPE) { // void
} else {
throw new IllegalArgumentException("Not a primitive: "+declaredClass);
}
//枚举类型写入
} else if (declaredClass.isEnum()) { // enum
UTF8.writeString(out, ((Enum)instance).name());
//hadoop的Writable类型写入
} else if (Writable.class.isAssignableFrom(declaredClass)) { // Writable
UTF8.writeString(out, instance.getClass().getName());
((Writable)instance).write(out);
} else {
throw new IOException("Can't write: "+instance+" as "+declaredClass);
}
}
对于readObject(in, this, this.conf)方法:该方法用于反序列化,在ObjectWritable对象内部封装了一个基本数据类型的注册表
通过if语句条件实现基本数据类型的反序列化,而对于实现了Writbale接口的封装数据,则是通过Conf对象获取其类声明,其反序列化的
实例化也是调用WritableFactories工程去实例化,最后在存储反序列化的值。
public static Object readObject(DataInput in, Configuration conf)
throws IOException {
return readObject(in, null, conf);
}
/** Read a {@link Writable}, {@link String}, primitive type, or an array of
* the preceding. */
@SuppressWarnings("unchecked")
public static Object readObject(DataInput in, ObjectWritable objectWritable, Configuration conf)
throws IOException {
//获取反序列化的名字
String className = UTF8.readString(in);
//假设为基本数据类型
Class<?> declaredClass = PRIMITIVE_NAMES.get(className);
/*
* 判断是否为基本数据类型,不是则为空,则为Writable类型,
* 对于Writable类型从Conf配置文件中读取类名,
* 在这里只是获取类名,而并没有反序列化对象
*/
if (declaredClass == null) {
try {
declaredClass = conf.getClassByName(className);
} catch (ClassNotFoundException e) {
throw new RuntimeException("readObject can't find class " + className, e);
}
}
//基本数据类型
Object instance;
//为基本数据类型,逐一反序列化
if (declaredClass.isPrimitive()) { // primitive types
if (declaredClass == Boolean.TYPE) { // boolean
instance = Boolean.valueOf(in.readBoolean());
} else if (declaredClass == Character.TYPE) { // char
instance = Character.valueOf(in.readChar());
} else if (declaredClass == Byte.TYPE) { // byte
instance = Byte.valueOf(in.readByte());
} else if (declaredClass == Short.TYPE) { // short
instance = Short.valueOf(in.readShort());
} else if (declaredClass == Integer.TYPE) { // int
instance = Integer.valueOf(in.readInt());
} else if (declaredClass == Long.TYPE) { // long
instance = Long.valueOf(in.readLong());
} else if (declaredClass == Float.TYPE) { // float
instance = Float.valueOf(in.readFloat());
} else if (declaredClass == Double.TYPE) { // double
instance = Double.valueOf(in.readDouble());
} else if (declaredClass == Void.TYPE) { // void
instance = null;
} else {
throw new IllegalArgumentException("Not a primitive: "+declaredClass);
}
} else if (declaredClass.isArray()) { // array
int length = in.readInt();
instance = Array.newInstance(declaredClass.getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(instance, i, readObject(in, conf));
}
} else if (declaredClass == String.class) { // String类型的反序列化
instance = UTF8.readString(in);
} else if (declaredClass.isEnum()) { // enum的反序列化
instance = Enum.valueOf((Class<? extends Enum>) declaredClass, UTF8.readString(in));
} else { // Writable
Class instanceClass = null;
String str = "";
try {
//剩下的从Conf对象中获取类型Class
str = UTF8.readString(in);
instanceClass = conf.getClassByName(str);
} catch (ClassNotFoundException e) {
throw new RuntimeException("readObject can't find class " + str, e);
}
/*
* 带用了WritableFactories工厂去new instanceClass(实现了Writable接口)对象出来
* 在调用实现Writable对象自身的反序列化方法
*/
Writable writable = WritableFactories.newInstance(instanceClass, conf);
writable.readFields(in);
instance = writable;
if (instanceClass == NullInstance.class) { // null
declaredClass = ((NullInstance)instance).declaredClass;
instance = null;
}
}
//最后存储反序列化后待封装的ObjectWritable对象
if (objectWritable != null) { // store values
objectWritable.declaredClass = declaredClass;
objectWritable.instance = instance;
}
return instance;
}
对于Null类型的封装,在ObjectWritable内部封装了一个Nullinstance
private static class NullInstance extends Configured implements Writable {
private Class<?> declaredClass;
public NullInstance() { super(null); }
public NullInstance(Class declaredClass, Configuration conf) {
super(conf);
this.declaredClass = declaredClass;
}