hdfs中ReflectionUtils在實例化ObjectWritable內部類NullIn...

hadoop版本:1.0.3 java

問題描述: 工具

在研究DataNode啓動代碼的時候遇到這麼一個問題,經過Hadoop工具類ReflectionUtils反射生成NullInstance實例時,NullInstance父類Configured的成員變量conf未正確賦值,因爲未正確賦值,在隨後的代碼中會拋出空指針異常。 oop

問題分析: spa

Hadoop在ObjectWritable對象的反序列化過程當中,對於非基本類型都會經過反射生成對應的類實例,在這個過程當中還會根據類是否是接口Configurable的實現類,進行成員變量conf的賦值操做。相關代碼以下: 指針


ObjectWritable:
public static Object readObject(DataInput in, ObjectWritable objectWritable, Configuration conf)
    throws IOException {
      ... 
      Writable writable = WritableFactories.newInstance(instanceClass, conf);
      writable.readFields(in);
      instance = writable;

      ...
      
  }

WritableFactories:
public static Writable newInstance(Class<? extends Writable> c, Configuration conf) {
    WritableFactory factory = WritableFactories.getFactory(c);
    if (factory != null) {
      Writable result = factory.newInstance();
      if (result instanceof Configurable) {
        ((Configurable) result).setConf(conf);
      }
      return result;
    } else {
      return ReflectionUtils.newInstance(c, conf);
    }
  }

ReflectionUtils:
public static <T> T newInstance(Class<T> theClass, Configuration conf) {
		T result;
		try {
			Constructor<T> meth = (Constructor<T>) CONSTRUCTOR_CACHE
					.get(theClass);
			if (meth == null) {
				meth = theClass.getDeclaredConstructor(EMPTY_ARRAY);
				meth.setAccessible(true);
				CONSTRUCTOR_CACHE.put(theClass, meth);
			}
			result = meth.newInstance();
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
		setConf(result, conf);
		return result;
	}
public static void setConf(Object theObject, Configuration conf) {
 if (conf != null) {
      if (theObject instanceof Configurable) {
            ((Configurable) theObject).setConf(conf);
      }
      setJobConf(theObject, conf);
 }
} 

回到NullInstance的類定義,因爲繼承了類Configured,意味着NullInstance須要在實例化的時候,初始化conf對象。若是conf對象未被正確初始化,可能會出現程序異常,如空指針錯誤,conf爲空,在執行下面代碼的時候,會拋空指針異常: code

NullInstance:
public void readFields(DataInput in) throws IOException {
      String className = Text.readString(in);
      declaredClass = PRIMITIVE_NAMES.get(className);
      if (declaredClass == null) {
        try {
          //此處調用getConf()可能拿到null
          declaredClass = getConf().getClassByName(className); 
        } catch (ClassNotFoundException e) {
          throw new RuntimeException(e.toString());
        }
      }
    }
問題解決:

在ReflectionUtils的方法setConf中增長代碼: 對象

if(Configured.class.isAssignableFrom(theObject.getClass())){
	((Configured)theObject).setConf(conf);
}
相關文章
相關標籤/搜索