<?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
使用了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测试注释
- 通常,第一次进行编组的时间最长。
- JAXB和SAX的内存使用情况相似。 10,000个人的档案约为2 Meg,而250,000的档案是36 – 38 Meg档案。 DOM内存使用率更高。 对于10,000个人档案,它是6 Meg,对于250,000个人档案,它是大于130 Meg。
- 纯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测试注释
- 同样,第一次进行编组通常会成比例地变长。
- 同样,SAX和JAXB的内存使用情况非常相似。 两者都好得多
比DOM。 结果与测试1非常相似。
- JAXB(StAX)进近时间已大大缩短。 这是由于
正在使用StAX解析的Woodstox实现。
- 纯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测试注释:
- 总体而言,JDK 7的性能要好得多。 有一些异常-第一次解析100个人和10,000个人档案。
- 内存使用量略高。 对于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所有测试
- 没有对100人文件进行内存分析。 内存使用量太小,因此将没有意义的信息。
- 首次初始化JAXB上下文最多需要0.5秒。 这不包括在测试结果中,因为这只是第一次。 之后,JVM会非常快地初始化上下文(始终小于5毫秒)。 如果您在使用任何JAXB实现时都注意到此行为,请考虑在启动时进行初始化。
- 这些测试是一个非常简单的XML文件。 实际上,将会有更多的对象类型和更复杂的XML。 但是,这些测试仍应提供指导。
结论:
- 纯SAX的性能时间略好于JAXB,但仅适用于非常大的文件。 除非使用的文件非常大,否则性能差异不值得担心。 JAXB的编程模型优势克服了SAX编程模型的复杂性。 别忘了JAXB也像DOM一样提供随机访问。 SAX不提供此功能。
- 如果使用JAXB / StAX,则使用Woodstox的性能时间看起来要好得多。
- 使用64位JDK 7的性能看起来要好得多。 内存使用情况看起来略高。
参考:来自都柏林技术博客的 JCG合作伙伴 Alex Staveley的JAXB,SAX,DOM性能 。
相关文章 :
- 使用JAXB从XSD生成XML
- 将对象映射到多个XML模式–天气示例
- 使用Spring MVC开发Restful Web服务
- 具有简单框架教程的Android XML绑定
- 使用XML Pull增强Android XML解析
翻译自: https://www.javacodegeeks.com/2011/12/jaxb-sax-dom-performance.html