1. 程式人生 > >dubbo解耦service層和action層操作model屬性問題

dubbo解耦service層和action層操作model屬性問題

在開發中,採用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一定注意,子類不要去重寫父類的屬性。