zoukankan      html  css  js  c++  java
  • JAXB性能优化

    前言:
      之前在查阅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代价这么高昂, 只是得出了一个小结论, 权当笔记.

  • 相关阅读:
    不用keytool,tomcat打开https
    sqlserver获取某一张表中的所有列中的最大长度
    不用keytool,tomcat打开https
    到底私钥和公钥哪个是用来加密 哪个是用来解密的
    空间支持php解压
    到底私钥和公钥哪个是用来加密 哪个是用来解密的
    sqlserver获取某一张表中的所有列中的最大长度
    数字签名(代码签名)流程
    功夫电影中非常经典(武术非常实用)
    数字签名(代码签名)流程
  • 原文地址:https://www.cnblogs.com/mumuxinfei/p/9019878.html
Copyright © 2011-2022 走看看