前言:
  之前在查阅jaxb相关资料的同时, 也看到了一些关于性能优化的点. 主要集中于对象和xml互转的过程中, 确实有些实实在在需要注意的点. 这边浅谈jaxb性能优化的一个思路.

案列:
  先来构造一个简单的例子:

    @Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
@XmlRootElement(name="txn")
@XmlAccessorType(XmlAccessType.FIELD)
public static class TNode { @XmlElement(name="key", required = true)
private String key; @XmlElement(name="value", required = true)
private String value; }

  注: 这个基本的映射对象类

	public static <T> String writeAsString(T t) {
try {
JAXBContext jc = JAXBContext.newInstance(t.getClass());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); StringWriter writer = new StringWriter();
marshaller.marshal(t, writer);
return writer.toString();
} catch (JAXBException ex) {
ex.printStackTrace();
}
return null;
}

  注: 这是最经典的java对象转化为xml的代码片段.

    @Test
public void testPref() { TNode node = new TNode("key", "value"); // *) 迭代重复的次数
int numIter = 1000;
long startTime = System.currentTimeMillis();
for ( int i = 0; i < numIter; i++ ) {
writeAsString(node);
}
long endTime = System.currentTimeMillis(); System.out.println(String.format("iter num: %d, consume: %dms, avg: %.2fms",
numIter, (endTime - startTime), (endTime - startTime) * 1.0 / numIter)); }

  注: 这是实际执行的性能评估代码, 注意这边的迭代次数.

  测试一下在迭代100/1000/10000次的, 总耗时及平均耗时.

iter num: 100, consume: 2001ms, avg: 20.01ms
iter num: 1000, consume: 11020ms, avg: 11.02ms
iter num: 10000, consume: 108290ms, avg: 10.83ms

  大致维持在10ms, 这算一个比较酸涩的结果, 如果映射是个复杂的对象, 其耗时会成倍的增加, 对于追求高并发低延时的互联网应用而言, 略显尴尬, redis平均为1ms, mysql/mongo基本维持在10ms范围内. 因此jaxb虽然非常好用, 但是性能需要优化.

瓶颈定位&优化:
  经过测试, 基本聚焦在JAXBContext.newInstance这个方法中. 其生成的JAXBContext实例代价高, 但其是无状态(线程安全), 我们可以想到的一个优化措施是缓存.
  对转换代码做下小改动:

private static ConcurrentHashMap<Class, JAXBContext> jaxbContMap
= new ConcurrentHashMap<Class, JAXBContext>(); public static <T> String writeAsString(T t) {
try {
JAXBContext jc = jaxbContMap.get(t.getClass());
if ( jc == null ) {
synchronized (t.getClass()) {
jc = JAXBContext.newInstance(t.getClass());
jaxbContMap.put(t.getClass(), jc);
}
}
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); StringWriter writer = new StringWriter();
marshaller.marshal(t, writer);
return writer.toString();
} catch (JAXBException ex) {
ex.printStackTrace();
}
return null;
}

  注: 引入ConcurrentHashMap来缓存类类型到具体的JAXBContext实例.
  再测试100/1000/10000调用次数的平均时耗, 结果如下:

    iter num: 100, consume: 295ms, avg: 2.95ms
iter num: 1000, consume: 1325ms, avg: 1.33ms
iter num: 10000, consume: 5688ms, avg: 0.57ms

  结果非常令人欣喜, 耗时能够维持在1ms以内, 优化提升效果很明显.

总结:
  总的来说, 这也是jaxb在使用过程的一个坑, 如果线上应用, 切记改为下面的方式优化, ^_^, 本文没有深入研究为何JAXBContext.newInstance代价这么高昂, 只是得出了一个小结论, 权当笔记.

最新文章

  1. SDWebImage源码解读之SDWebImageDownloaderOperation
  2. Quality 是什么?
  3. Python基础10- 函数之内部函数与强制转换
  4. 好看的css3按钮和文本框
  5. 【堆】【kd-tree】bzoj2626 JZPFAR
  6. poj2778
  7. 基于Flume的美团日志收集系统(一)架构和设计
  8. Windows服务定时运行,判断当前时间是否在配置时间段内
  9. JAVA中使用Redis
  10. 获取iOS应用的版本号和app名称
  11. 多线程学习之二坚不可摧模式Immutable pattern
  12. FastDFS接口API文档说明
  13. PHP实现仿Google分页效果的分页函数
  14. 串口调试者v2.1------开源c#串口调试工具
  15. 2017ecjtu-summer training #5 UVA10382
  16. JAVA---MYSQL 基本知识点 第二部分
  17. crontab下git命令无效
  18. H3C交换机IRF典型配置举例LACP MAD检测方式
  19. mysql binlog日志自动清理及手动删除
  20. 整合elk(1)(十二)

热门文章

  1. Django框架(一)
  2. [luogu P3275] [SCOI2011]糖果
  3. Vuejs实现轮播图
  4. Qt_qwt图形开发
  5. 微信订阅号,获取用户openid
  6. springboot aop 自定义注解方式实现一套完善的日志记录(完整源码)
  7. Python自然语言处理---TF-IDF模型
  8. EF-使用迁移技术让程序自动更新数据库表结构
  9. 几大principal
  10. 深入理解java虚拟机---虚拟机工具jstat(十七)