Hadoop-commons分析

 

hadoop的配置文件相关类 Configuration

所有大型的系统都有一套自己的配置系统或模块,用于方便系统扩展用,hadoop有自己独立的一套配置方式

采用XML文件,使用SAX解析

配置文件my-config.xml格式

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>  
  3. <configuration>  
  4.     <property>  
  5.         <name>name</name>  
  6.         <value>Girls Generation</value>  
  7.         <final>true</final>  
  8.         <description>The boys~</description>  
  9.     </property>  
  10. </configuration>  

 

可以加载多个配置文件如:

  1. Configuration cfg = new Configuration();  
  2. cfg.addResource(new URL("http://mytest.com/hadoop.xml"));  
  3. cfg.addResource(new FileInputStream("/data0/test/hadoop.xml"));  
  4. cfg.addResource(new Path("hdfs://hadoop-test/data/test.xml"));  
  5. cfg.addResource("mytest.xml");  

如果第一个配置文件f1.xml中的age字段是final的,则不会被第二个文件f2.xml中同名的元素覆盖;

反之则会覆盖

 

Configuration类的静态代码块中显示加载了hadoop相关的几个xml文件,都是通过类加载方式加载的

  1. static{  
  2.   //print deprecation warning if hadoop-site.xml is found in classpath  
  3.   ClassLoader cL = Thread.currentThread().getContextClassLoader();  
  4.   if (cL == null) {  
  5.     cL = Configuration.class.getClassLoader();  
  6.   }  
  7.   addDefaultResource("core-default.xml");  
  8.   addDefaultResource("core-site.xml");  
  9. }  

 

加载配置是延迟加载的,会优先加载hadoop相关的XML文件,然后才是自定义的XML文件

  1. private void loadResources(Properties properties,  
  2.                            ArrayList resources,  
  3.                            boolean quiet) {  
  4.   if(loadDefaults) {  
  5.     for (String resource : defaultResources) {  
  6.       loadResource(properties, resource, quiet);  
  7.     }  
  8.     
  9.     //support the hadoop-site.xml as a deprecated case  
  10.     if(getResource("hadoop-site.xml")!=null) {  
  11.       loadResource(properties, "hadoop-site.xml", quiet);  
  12.     }  
  13.   }  
  14.     
  15.   for (Object resource : resources) {  
  16.     loadResource(properties, resource, quiet);  
  17.   }  
  18. }  

 

配置文件支持表达式的方式

  1. <property>  
  2.     <name>hadoop.tmp.dir</name>  
  3.     <value>/data0/hadoop/tmp</value>  
  4. </property>  
  5.   
  6. <property>  
  7.     <name>dir</name>  
  8.     <value>${hadoop.tmp.dir}/data</value>  
  9. </property>  

而表达式可以嵌套,${path1}又引用了${path2},path2又引用了${path3}

这个嵌套深度最多是20次

表达式可以写在配置文件中,也可以在启动时通过 -D 参数传入

 

此外还有一个接口Configurable,实现了这个接口的类都表示可以配置的

  1. public interface Configurable {  
  2.   /** Set the configuration to be used by this object. */  
  3.   void setConf(Configuration conf);  
  4.   /** Return the configuration used by this object. */  
  5.   Configuration getConf();  
  6. }  

 

 

 

 

hadoop的序列化

关于序列化有三种作用:

1.作为一种持久化格式,比如对象编码后存储到磁盘上

2.作为一种通信数据格式,将一个虚拟机上的对象通过网络传输到另一个虚拟机上

3.作为一种拷贝克隆机制,将对象序列化到内存中再反序列化读取

hadoop有自己的序列化机制,它主要用来解决1)和2)两种情况的,hadoop序列化使用方式

  1. public void run() throws IOException {  
  2.     ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  3.     DataOutputStream dos = new DataOutputStream(baos);  
  4.     IntWritable iw = new IntWritable(9527);  
  5.     iw.write(dos);  
  6.     dos.close();  
  7.                System.out.println(new String(baos.toByteArray()));  
  8.      }  

 

而IntWritable的write()函数很简单

  1. public void write(DataOutput out) throws IOException {  
  2.   out.writeInt(value);  
  3. }  

 

DataOutputStream的write实际上就是把int分别按位取然后跟0xFF做与运算,最后写入

  1. public final void writeInt(int v) throws IOException {  
  2.     out.write((v >>> 24) & 0xFF);  
  3.     out.write((v >>> 16) & 0xFF);  
  4.     out.write((v >>>  8) & 0xFF);  
  5.     out.write((v >>>  0) & 0xFF);  
  6.     incCount(4);  
  7. }  

  

 

 

Writable相关的类图


 

Writable的子类

 

序列化类中还有一个可变长度vint和vlong,vint具体实现是用vlong去做的,可变长度vlong可以有效节省空间 

可变长度vlong的写入源码

  1. public static void writeVLong(DataOutput stream, long i) throws IOException {  
  2.   if (i >= -112 && i <= 127) {  
  3.     stream.writeByte((byte)i);  
  4.     return;  
  5.   }  
  6.       
  7.   int len = -112;  
  8.   if (i < 0) {  
  9.     i ^= -1L; // take one's complement'  
  10.     len = -120;  
  11.   }  
  12.       
  13.   long tmp = i;  
  14.   while (tmp != 0) {  
  15.     tmp = tmp >> 8;  
  16.     len--;  
  17.   }  
  18.       
  19.   stream.writeByte((byte)len);  
  20.       
  21.   len = (len < -120) ? -(len + 120) : -(len + 112);  
  22.       
  23.   for (int idx = len; idx != 0; idx--) {  
  24.     int shiftbits = (idx - 1) * 8;  
  25.     long mask = 0xFFL << shiftbits;  
  26.     stream.writeByte((byte)((i & mask) >> shiftbits));  
  27.   }  
  28. }  

  

可变长度vlong的读取源码

  1. public static long readVLong(DataInput stream) throws IOException {  
  2.   byte firstByte = stream.readByte();  
  3.   int len = decodeVIntSize(firstByte);  
  4.   if (len == 1) {  
  5.     return firstByte;  
  6.   }  
  7.   long i = 0;  
  8.   for (int idx = 0; idx < len-1; idx++) {  
  9.     byte b = stream.readByte();  
  10.     i = i << 8;  
  11.     i = i | (b & 0xFF);  
  12.   }  
  13.   return (isNegativeVInt(firstByte) ? (i ^ -1L) : i);  
  14. }  
  15.   
  16. public static int decodeVIntSize(byte value) {  
  17.   if (value >= -112) {  
  18.     return 1;  
  19.   } else if (value < -120) {  
  20.     return -119 - value;  
  21.   }  
  22.   return -111 - value;  
  23. }  
  24.   
  25. public static boolean isNegativeVInt(byte value) {  
  26.   return value < -120 || (value >= -112 && value < 0);  
  27. }  

 

hadoop针对java的基本类型,字符串,枚举,Writable,空值等提供了一个ObjectWritable类,可以写入多种类型,这个类也适用于远程过程调用(RPC) 

ObjectWritable#writObject源码,就是先写入这个类的名称,然后判断类中的变量是数组,枚举还是普通类型,然后再依次写入到流中

  1. public static void writeObject(DataOutput out, Object instance,  
  2.                                Class declaredClass,   
  3.                                Configuration conf) throws IOException {  
  4.   
  5.   if (instance == null) {                       // null  
  6.     instance = new NullInstance(declaredClass, conf);  
  7.     declaredClass = Writable.class;  
  8.   }  
  9.   
  10.   UTF8.writeString(out, declaredClass.getName()); // always write declared  
  11.   
  12.   if (declaredClass.isArray()) {                // array  
  13.     int length = Array.getLength(instance);  
  14.     out.writeInt(length);  
  15.     for (int i = 0; i < length; i++) {  
  16.       writeObject(out, Array.get(instance, i),  
  17.                   declaredClass.getComponentType(), conf);  
  18.     }  
  19.       
  20.   } else if (declaredClass == String.class) {   // String  
  21.     UTF8.writeString(out, (String)instance);  
  22.       
  23.   } else if (declaredClass.isPrimitive()) {     // primitive type  
  24.   
  25.     if (declaredClass == Boolean.TYPE) {        // boolean  
  26.       out.writeBoolean(((Boolean)instance).booleanValue());  
  27.     } else if (declaredClass == Character.TYPE) { // char  
  28.       out.writeChar(((Character)instance).charValue());  
  29.     } else if (declaredClass == Byte.TYPE) {    // byte  
  30.       out.writeByte(((Byte)instance).byteValue());  
  31.     } else if (declaredClass == Short.TYPE) {   // short  
  32.       out.writeShort(((Short)instance).shortValue());  
  33.     } else if (declaredClass == Integer.TYPE) { // int  
  34.       out.writeInt(((Integer)instance).intValue());  
  35.     } else if (declaredClass == Long.TYPE) {    // long  
  36.       out.writeLong(((Long)instance).longValue());  
  37.     } else if (declaredClass == Float.TYPE) {   // float  
  38.       out.writeFloat(((Float)instance).floatValue());  
  39.     } else if (declaredClass == Double.TYPE) {  // double  
  40.       out.writeDouble(((Double)instance).doubleValue());  
  41.     } else if (declaredClass == Void.TYPE) {    // void  
  42.     } else {  
  43.       throw new IllegalArgumentException("Not a primitive: "+declaredClass);  
  44.     }  
  45.   } else if (declaredClass.isEnum()) {         // enum  
  46.     UTF8.writeString(out, ((Enum)instance).name());  
  47.   } else if (Writable.class.isAssignableFrom(declaredClass)) { // Writable  
  48.     UTF8.writeString(out, instance.getClass().getName());  
  49.     ((Writable)instance).write(out);  
  50.   
  51.   } else {  
  52.     throw new IOException("Can't write: "+instance+" as "+declaredClass);  
  53.   }  
  54. }  

 

 

hadoop序列化框架

1.Avro

2.Thrift

3.Google protocol Buffer

hadoop自身的简单的序列化框架API(在org.apache.hadoop.io.serializer包中)的类图


 

 

 

 

 

参考

抽象工厂模式-与-工厂方法模式区别

《JAVA与模式》之抽象工厂模式

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值