dubbo解耦service層和action層操作model屬性問題
阿新 • • 發佈:2018-12-20
在開發中,採用SSM框架,通過dubbo將服務層和action層解耦。多人操作一個實體Model(子),剛好這個Model又繼承另一個Model(父),一哥們在不知情的情況下,在子Model中定義了一個父Model已經存在的屬性。查詢後,發現這一欄位的值為null,轉化為json輸出到前端頁面時這一屬性直接丟失了。通過debug發現,在service層查詢後封裝到Model時,資料是存在的,但是一到action層,再向頁面返回時,這一屬性已經為null了。
針對這一現象,推斷如下:
dubbo序列化(在service層) ---->傳輸 ---->dubbo反序列化(在Action層),應該是在反序列化的過程中把子Model重寫的屬性給覆蓋了。
根據這一推斷,去閱讀dubbo原始碼,如下:
/** * Creates a map of the classes fields. */ protected HashMap getFieldMap(Class cl) { HashMap fieldMap = new HashMap(); for (; cl != null; cl = cl.getSuperclass()) { Field []fields = cl.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; if (Modifier.isTransient(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) continue; else if (fieldMap.get(field.getName()) != null) //由子類到父類,子類放入,父類不再放入,Map的key唯一,即屬性對應的解析器唯一 continue; // XXX: could parameterize the handler to only deal with public try { field.setAccessible(true); } catch (Throwable e) { e.printStackTrace(); } Class type = field.getType(); FieldDeserializer deser; if (String.class.equals(type)) deser = new StringFieldDeserializer(field); else if (byte.class.equals(type)) { deser = new ByteFieldDeserializer(field); } else if (short.class.equals(type)) { deser = new ShortFieldDeserializer(field); } else if (int.class.equals(type)) { deser = new IntFieldDeserializer(field); } else if (long.class.equals(type)) { deser = new LongFieldDeserializer(field); } else if (float.class.equals(type)) { deser = new FloatFieldDeserializer(field); } else if (double.class.equals(type)) { deser = new DoubleFieldDeserializer(field); } else if (boolean.class.equals(type)) { deser = new BooleanFieldDeserializer(field); } else if (java.sql.Date.class.equals(type)) { deser = new SqlDateFieldDeserializer(field); } else if (java.sql.Timestamp.class.equals(type)) { deser = new SqlTimestampFieldDeserializer(field); } else if (java.sql.Time.class.equals(type)) { deser = new SqlTimeFieldDeserializer(field); } else { deser = new ObjectFieldDeserializer(field); } fieldMap.put(field.getName(), deser); } } return fieldMap; }
上面這段程式碼是構造解析時的屬性解析器。
public Object readObject(AbstractHessianInput in, //in ----> [email protected] Object obj, String []fieldNames) throws IOException { try { int ref = in.addRef(obj); for (int i = 0; i < fieldNames.length; i++) { //遍歷所有的fieldName String name = fieldNames[i]; FieldDeserializer deser = (FieldDeserializer) _fieldMap.get(name);//反序列化父類時,拿到反序列化器,但此時父類屬性的值為null if (deser != null) //不為null,即存在反序列化器,反序列化屬性 deser.deserialize(in, obj); else in.readObject();//不識別,直接讀取 } Object resolve = resolve(obj);//解析物件 if (obj != resolve)//不相等,解析成功,返回resolve in.setRef(ref, resolve);//重置引用關係 return resolve; } catch (IOException e) { throw e; } catch (Exception e) { throw new IOExceptionWrapper(obj.getClass().getName() + ":" + e, e); } }
fieldNames是一個String陣列,存放子Model的所有屬性,包括從父Model繼承得到的屬性,並且子Model中的屬性在陣列前面,父Model屬性位於陣列靠後的元素。這樣解析後,利用反射賦值,相當於給例項重新set了父類的屬性值,而父類屬性值為null,這樣就造成了前面提到的問題。
/**
* 字串反序列化
*/
static class StringFieldDeserializer extends FieldDeserializer {
private final Field _field;
StringFieldDeserializer(Field field)
{
_field = field;
}
void deserialize(AbstractHessianInput in, Object obj)
throws IOException
{
String value = null;
try {
value = in.readString();
_field.set(obj, value); //利用反射給物件設定屬性
} catch (Exception e) {
logDeserializeError(_field, obj, value, e);
}
}
}
所以在使用dubbo解耦service層和action層時,操作的實體Model一定注意,子類不要去重寫父類的屬性。