雨翔河
首页
列表
关于
xstream 使用的第二个小问题
2019-04-03 06:29
之前说过一个xstream使用过程中遇到的一个小问题: [Xstream 对象使用不当导致 CPU 居高不下](https://yuxianghe.net/blog/22) 这次又遇到一个,情况是这样的: 当在生产环境使用`xstream`进行解析xml转换为java对象的时候有一个缓存问题, 如果有两个不相干的接口,这两个接口唯一的共同点就是使用了xstream解析返回结果,且巧合的是两个接口的返回结果xml格式一模一样。 xml结果格式如下: ``` <response><success>true</success></response> ``` 这两个接口都定义了一个bean,且结构一样,A对象定义如下: ``` @XStreamAliasType(value="response") public class Response1 { @XStreamAsAttribute private String success; @XStreamAsAttribute private String errorMsg; public String getSuccess() { return success; } public void setSuccess(String success) { this.success = success; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } } ``` B对象定义如下: ``` @XStreamAliasType(value="response") public class Response2 { @XStreamAsAttribute private String success; @XStreamAsAttribute private String errorMsg; public String getSuccess() { return success; } public void setSuccess(String success) { this.success = success; } public String getErrorMsg() { return errorMsg; } public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } } ``` 解析的操作大致如下: ``` public static void main(String[] args) throws InterruptedException { String resp = "<response><success>true</success></response>"; Response1 response1 = (Response1) XmlUtil.xml2Object(resp, new Class[] { Response1.class }); String a = response1.getSuccess(); Object object = XmlUtil.xml2Object(resp, new Class[] { Response2.class }); Response2 response2 = (Response2) object; String b = response2.getSuccess(); System.out.println(a+ " : " +b); } ``` xmlUtil: ``` public class XmlUtil { public static Object xml2Object(String inputXml, Class<?>[] types){ if (StringUtils.isBlank(inputXml)) { return null; } XStream xstream = XStreamUtil.getInstance(); xstream.processAnnotations(types); return xstream.fromXML(inputXml); } } ``` 当A对象和B对象都在从xml解析到对象的时候会引发一个错误: ``` com.xxx.Response2 cannot be cast to com.xxx.Response1 ``` 根本原因: XStream本身在进行讲xml转换到对象的时候,对每一次操作的类都进行了对象缓存,存储在一个map里面,这个map的key是你要解析的xml的头结点名字,在这里就是response, 当解析xml的时候会读取这个map里面的key为response的value,这样可以直接在缓存里面拿到class,达到解析速度更快。 这就是报错的根本原因。 xstream里的`com.thoughtworks.xstream.mapper.CachingMapper`类源码是这样定义的: ``` private transient Map realClassCache; public Class realClass(String elementName) { Object cached = realClassCache.get(elementName); if (cached != null) { if (cached instanceof Class) { return (Class)cached; } throw (XStreamException)cached; } try { Class result = super.realClass(elementName); realClassCache.put(elementName, result); return result; } catch (ForbiddenClassException e) { realClassCache.put(elementName, e); throw e; } catch (CannotResolveClassException e) { realClassCache.put(elementName, e); throw e; } } ``` 可以看出使用 elementName 做缓存,这一点我个人觉得还是有待商榷,为了性能埋下了一个坑。
类型:工作
标签:xstream,java
Copyright © 雨翔河
我与我周旋久
独孤影
开源实验室