<?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性能 。
相关文章 :
翻译自: https://www.javacodegeeks.com/2011/12/jaxb-sax-dom-performance.html