JAXB,SAX,DOM性能

这篇文章探讨了使用多种不同方法将XML文档编组为Java对象的性能。 XML文档非常简单。 它包含一个Person实体的集合。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persons>
    <person>
        <id>person0</id>
        <name>name0</name>
    </person>
    <person>
         <id>person1</id>
         <name>name1</name>
    </person>
...

XML中的Person实体有一个对应的Person Java对象
..

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "id",
    "name"
})
public class Person {
    private String id;
    private String name;
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String value) {
        this.name = value;
    }
}

和一个PersonList对象代表一个Persons集合。

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "persons")
public class PersonList {
    @XmlElement(name="person")
    private List<person> personList = new ArrayList<person>();
 
    public List<person> getPersons() {
        return personList;
    }
 
    public void setPersons(List<person> persons) {
        this.personList = persons;
    }
}

研究的方法是:

  • 各种口味的JAXB
  • 萨克斯
  • DOM
在所有情况下,目标都是使XML文档中的实体到达相应的Java对象。 在Person和PersonList POJOS上的JAXB批注用于JAXB测试中。 可以在SAX和DOM测试中使用相同的类(注释将被忽略)。 最初是参考

使用了JAXB,SAX和DOM的实现。 然后使用Woodstox STAX解析。 在某些JAXB解组测试中会调用此方法。

测试是在运行Windows 7的戴尔笔记本电脑,2.1 GHz奔腾双核CPU上进行的。

测试1 –使用JAXB解组Java文件。

@Test
public void testUnMarshallUsingJAXB() throws Exception {
    JAXBContext jc = JAXBContext.newInstance(PersonList.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    PersonList obj = (PersonList)unmarshaller.unmarshal(new File(filename));
}

测试1说明了JAXB的编程模型有多简单。 从XML文件到Java对象非常容易。 无需参与编组和解析的精妙细节。

测试2 –使用JAXB解组流源


测试2与测试1类似,不同之处在于,这次流源对象包装在文件对象周围。 Streamsource对象向JAXB实现提供提示以流式传输文件。

@Test
public void testUnMarshallUsingJAXBStreamSource() throws Exception {
    JAXBContext jc = JAXBContext.newInstance(PersonList.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    StreamSource source = new StreamSource(new File(filename));
    PersonList obj = (PersonList)unmarshaller.unmarshal(source);
}

测试3 –使用JAXB解组StAX XMLStreamReader

再次类似于测试1,除了这次XMLStreamReader实例包装了由JAXB编组的FileReader实例。

@Test
public void testUnMarshallingWithStAX() throws Exception {
    FileReader fr = new FileReader(filename);
    JAXBContext jc = JAXBContext.newInstance(PersonList.class);
    Unmarshaller unmarshaller = jc.createUnmarshaller();
    XMLInputFactory xmlif = XMLInputFactory.newInstance();
    XMLStreamReader xmler = xmlif.createXMLStreamReader(fr);
    PersonList obj = (PersonList)unmarshaller.unmarshal(xmler);
}

测试4 –仅使用DOM

该测试不使用JAXB,而是仅使用JAXP DOM方法。 这意味着比任何JAXB方法都需要更多的代码。

@Test
public void testParsingWithDom() throws Exception {
    DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder builder = domFactory.newDocumentBuilder();
    Document doc = builder.parse(filename);
    List personsAsList = new ArrayList();
    NodeList persons = doc.getElementsByTagName("persons");
    for (int i = 0; i <persons.getLength(); i++) {
        Element person = (Element)persons.item(i);
        NodeList children = (NodeList)person.getChildNodes();
        Person newperson = new Person();
        for (int j = 0; j < children.getLength(); j++){
            Node child = children.item(i);
            if (child.getNodeName().equalsIgnoreCase("id")) {
                newperson.setId(child.getNodeValue());
            } else if (child.getNodeName().equalsIgnoreCase("name")) {
                newperson.setName(child.getNodeValue());
            }
        }
        personsAsList.add(newperson);
    }
}

测试5 –仅使用SAX测试5不使用JAXB,而使用SAX来解析XML文档。 与任何JAXB方法相比,SAX方法涉及更多的代码和更多的复杂性。 开发人员必须参与文档的解析。

@Test
public void testParsingWithSAX() throws Exception {
    SAXParserFactory factory = SAXParserFactory.newInstance();
    SAXParser saxParser = factory.newSAXParser();
    final List<person> persons = new ArrayList<person>();
    DefaultHandler handler = new DefaultHandler() {
        boolean bpersonId = false;
        boolean bpersonName = false;
        public void startElement(String uri, String localName,String qName,    Attributes attributes) throws SAXException {
     if (qName.equalsIgnoreCase("id")) {
                bpersonId = true;
                Person person = new Person();
                persons.add(person);
            } else if (qName.equalsIgnoreCase("name")) {
                bpersonName = true;
            }
        }
        public void endElement(String uri, String localName, String qName) throws SAXException {
        }
        public void characters(char ch[], int start, int length) throws SAXException {
     if (bpersonId) {
                String personID = new String(ch, start, length);
                bpersonId = false;
                Person person = persons.get(persons.size() - 1);
                person.setId(personID);
            } else if (bpersonName) {
                String name = new String(ch, start, length);
                bpersonName = false;
                Person person = persons.get(persons.size() - 1);
                person.setName(name);
            }
        }
    };
    saxParser.parse(filename, handler);
}

对于包含Person实体集合的3个文件,该测试运行了5次。 第一个文件包含100个Person实体,大小为5K。 第二个包含10,000个实体,大小为500K,第三个包含250,000个Person实体,大小为15 Meg。 在任何情况下都不会使用任何XSD或进行任何验证。 结果在结果表中给出,其中不同运行时间用逗号分隔。

试验结果

首先使用32位JDK 1.6.26运行测试,并使用JDK附带的SAX,DOM和JAXB的参考实现。

解组类型 100人次(毫秒) 10K人次(毫秒) 25万人次(毫秒)
JAXB(默认) 48,13,5,4,4 78,52,47,50,50 1522、1457、1353、1308、1317
JAXB(流源) 11,6,3,3,2 44,44,48,45,43 1191、1364、1144、1142、1136
JAXB(StAX) 18,2,1,1,1 111、136、89、91、92 2693、3058、2495、2472、2481
DOM 16,2,2,2,2 89,50,55,53,50 1992、2198、1845、1776、1773
萨克斯 4,2,1,1,1 29,34,23,26,26 704、669、605、589,591



JDK 1.6.26测试注释

  1. 通常,第一次进行编组的时间最长。
  2. JAXB和SAX的内存使用情况相似。 10,000个人的档案约为2 Meg,而250,000的档案是36 – 38 Meg档案。 DOM内存使用率更高。 对于10,000个人档案,它是6 Meg,对于250,000个人档案,它是大于130 Meg。
  3. 纯SAX的性能更好。 特别是对于非常大的文件。

使用相同的JDK(1.6.26)再次运行完全相同的测试,但是这次使用了StAX解析的Woodstox实现。

解组类型 100人次(毫秒) 10K人次(毫秒) 25万人次(毫秒)
JAXB(默认) 168,3,5,8,3 294、43、46、43、42 2055、1354、1328、1319、1319
JAXB(流源) 11,3,3,3,4 43,42,47,44,42 1147、1149、1176、1173、1159
JAXB(StAX) 30,0,1,1,0 67,37,40,37,37 1301、1236、1223、1336、1297
DOM 103,1,1,1,2 136,52,49,49,50 1882、1883、1821、1835、1822
萨克斯 4,2,2,1,1 31,25,25,38,25 613、609、607、595、613



JDK 1.6.26 + Woodstox测试注释

  1. 同样,第一次进行编组通常会成比例地变长。
  2. 同样,SAX和JAXB的内存使用情况非常相似。 两者都好得多

    比DOM。 结果与测试1非常相似。

  3. JAXB(StAX)进近时间已大大缩短。 这是由于

    正在使用StAX解析的Woodstox实现。

  4. 纯SAX的性能时间仍然是最好的。 尤其

    用于大文件。

再次运行完全相同的测试,但是这次我使用了JDK 1.7.02和StAX解析的Woodstox实现。

解组类型 100人次(毫秒) 10,000人次(毫秒) 250,000人次(毫秒)
JAXB(默认) 165,5,3,3,5 611,23,24,46,28 578、539、511、511、519
JAXB(流源) 13,4,3,4,3 43,24,21,26,22 678、520、509、504、627
JAXB(StAX) 21,1,0,0,0 300,69,20,16,16 637、487、422、435、458
DOM 22,2,2,2,2 420,25,24,23,24 1304、807、867、747、1189
萨克斯 7,2,2,1,1 169,15,15,19,14 366、364、363、360、358



JDK 7 + Woodstox测试注释:

  1. 总体而言,JDK 7的性能要好得多。 有一些异常-第一次解析100个人和10,000个人档案。
  2. 内存使用量略高。 对于SAX和JAXB,10,000人档案为2 – 4 Meg,对于250,000人档案为45 – 49 Meg。 对于DOM,它再次更高。 10,000人的档案5 – 7.5 Meg,250,000人的档案136 – 143 Meg。



注意:WRT所有测试

  1. 没有对100人文件进行内存分析。 内存使用量太小,因此将没有意义的信息。
  2. 首次初始化JAXB上下文最多需要0.5秒。 这不包括在测试结果中,因为这只是第一次。 之后,JVM会非常快地初始化上下文(始终小于5毫秒)。 如果您在使用任何JAXB实现时都注意到此行为,请考虑在启动时进行初始化。
  3. 这些测试是一个非常简单的XML文件。 实际上,将会有更多的对象类型和更复杂的XML。 但是,这些测试仍应提供指导。

结论:

  1. 纯SAX的性能时间略好于JAXB,但仅适用于非常大的文件。 除非使用的文件非常大,否则性能差异不值得担心。 JAXB的编程模型优势克服了SAX编程模型的复杂性。 别忘了JAXB也像DOM一样提供随机访问。 SAX不提供此功能。
  2. 如果使用JAXB / StAX,则使用Woodstox的性能时间看起来要好得多。
  3. 使用64位JDK 7的性能看起来要好得多。 内存使用情况看起来略高。

参考:来自都柏林技术博客的 JCG合作伙伴 Alex Staveley的JAXB,SAX,DOM性能

相关文章 :


翻译自: https://www.javacodegeeks.com/2011/12/jaxb-sax-dom-performance.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值