在开发中,采用SSM框架,通过dubbo将服务层和action层解耦。多人操作一个实体Model(子),刚好这个Model又继承另一个Model(父),一哥们在不知情的情况下,在子Model中定义了一个父Model已经存在的属性。查询后,发现这一字段的值为null,转化为json输出到前端页面时这一属性直接丢失了。通过debug发现,在service层查询后封装到Model时,数据是存在的,但是一到action层,再向页面返回时,这一属性已经为null了。
针对这一现象,推断如下:
dubbo序列化(在service层) ---->传输 ---->dubbo反序列化(在Action层),应该是在反序列化的过程中把子Model重写的属性给覆盖了。
根据这一推断,去阅读dubbo源码,如下:
com.alibaba.com.caucho.hessian.io.JavaDeserializer --->反序列化
/**
* 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;
}
上面这段代码是构造解析时的属性解析器。
//com.alibaba.com.caucho.hessian.io.JavaDeserializer.readObject(AbstractHessianInput, Object, String[])
public Object readObject(AbstractHessianInput in, //in ----> com.alibaba.com.caucho.hessian.io.Hessian2Input@5513639d
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,这样就造成了前面提到的问题。
com.alibaba.com.caucho.hessian.io.JavaDeserializer.StringFieldDeserializer
/**
* 字符串反序列化
*/
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一定注意,子类不要去重写父类的属性。