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