您的位置:首页 > 编程语言 > Java开发

如何提高Java解析pdm、ldm文件的性能

2017-03-05 00:00 337 查看
摘要: 如何提高Java解析pdm、ldm文件的性能。

1、为什么要提高解析pdm、ldm文件的性能

本人目前负责的一个项目中,要用到将pdm文件导入到MySQL的功能。最近遇到麻烦了,由于程序是部署在阿里云上(内存只有2G), 且pdm文件比较大(约10M+),每次解析pdm文件10秒钟,就会导致tomcat自动关闭,搞的我们很尴尬。常规的办法:

增加内存配置。考虑到成本问题,客户明确不会增加内存配置;

减少pdm文件大小。业务上就有这么大的文件,如果拆成小文件,解析完再组合,反而增加实现的复杂度;

优化代码。釜底抽薪,只能用这招了。

2、分析解析pdm、ldm文件常用的方法

解析节点的公共方法

public Object evaluate(String path, Object object, QName returnType) {
try {
return XPathFactory.newInstance().newXPath().evaluate(path, object, returnType);
} catch (XPathExpressionException e) {
// 捕捉到异常不进行抛出操作,直接返回null,由后续方法进行判断处理。
return null;
}
}

解析表的方法

public void parseTable(Node modelNode, MetaDomainDTO domain) {
NodeList tableList = (NodeList) evaluate(PATH_O_TABLE, modelNode, XPathConstants.NODESET);
List<MetaEntityDTO> entityList = new ArrayList<MetaEntityDTO>();
for (int i = 0; i < tableList.getLength(); i++) {
Node tableNode = tableList.item(i);// 获取table标签的解析对象
MetaEntityDTO table = new MetaEntityDTO();// 获取table实例

// 获取表id值
Long id = parseIdToLong(getAttrValue(TAG_ATTR_ID, tableNode));
// 获取<a:Name>标签内容作为描述信息
String name = getAttrContent(PATH_A_NAME, tableNode);
// 获取<a:Code>标签内容作为名称
String code = getAttrContent(PATH_A_CODE, tableNode);
// 获取<a:Comment>标签内容作为名称
String comment = getAttrContent(PATH_A_COMMENT, tableNode);

table.setEntityId(id);
table.setEntityName(name);
table.setEntityCode(code.toLowerCase());
table.setEntityComment(comment);
table.setDomainId(domain.getDomainId());
table.setVirtualId(id);
// 解析字段内容
parseColumn(tableNode, table);
// 解析键内容
parseKey(tableNode, table);
tableCache.put(id, table);
entityList.add(table);
}
domain.setEntityList(entityList);
}

以上是目前代码中的核心方法。为了定位到底是哪一步慢,我先减少pdm文件的大小,发现当文件是4M的时候解析需要15分钟,当文件是10M的时候,解析需要90分钟。我也观察了内存的使用情况,发现会经常发生GC。

pdm文件其实就是xml文件,我跳出了惯性思维,想想是否还有更加快的解析xml文件的方法呢?通过度娘,找到答案。

(1)DOM解析
DOM是html和xml的应用程序接口(API),以层次结构(类似于树型)来组织节点和信息片段,映射XML文档的结构,允许获取和操作文档的任意部分,是W3C的官方标准
【优点】
①允许应用程序对数据和结构做出更改。
②访问是双向的,可以在任何时候在树中上下导航,获取和操作任意部分的数据。
【缺点】
①通常需要加载整个XML文档来构造层次结构,消耗资源大。
【解析详解】
①构建Document对象:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = bdf.newDocumentBuilder();
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(xml文件);
Document doc = bd.parse(is);
②遍历DOM对象
Document: XML文档对象,由解析器获取
NodeList: 节点数组
Node: 节点(包括element、#text)
Element: 元素,可用于获取属性参数

(2)SAX(Simple API for XML)解析
流模型中的"推"模型分析方式。通过事件驱动,每发现一个节点就引发一个事件,事件推给事件处理器,通过回调方法完成解析工作,解析XML文档的逻辑需要应用程序完成
【优势】
①不需要等待所有数据都被处理,分析就能立即开始。
②只在读取数据时检查数据,不需要保存在内存中。
③可以在某个条件得到满足时停止解析,不必解析整个文档。
④效率和性能较高,能解析大于系统内存的文档。
【缺点】
①需要应用程序自己负责TAG的处理逻辑(例如维护父/子关系等),文档越复杂程序就越复杂。
②单向导航,无法定位文档层次,很难同时访问同一文档的不同部分数据,不支持XPath。
【原理】
简单的说就是对文档进行顺序扫描,当扫描到文档(document)开始与结束、元素(element)开始与结束时通知事件处理函数(回调函数),进行相应处理,直到文档结束
【事件处理器类型】
①访问XML DTD:DTDHandler
②低级访问解析错误:ErrorHandler
③访问文档内容:ContextHandler
【DefaultHandler类】
SAX事件处理程序的默认基类,实现了DTDHandler、ErrorHandler、ContextHandler和EntityResolver接口,通常做法是,继承该基类,重写需要的方法,如startDocument()
【创建SAX解析器】
SAXParserFactory saxf = SAXParserFactory.newInstance();
SAXParser sax = saxf.newSAXParser();
注:关于遍历
①深度优先遍历(Depthi-First Traserval)
②广度优先遍历(Width-First Traserval)

(3)JDOM(Java-based Document Object Model)
Java特定的文档对象模型。自身不包含解析器,使用SAX
【优点】
①使用具体类而不是接口,简化了DOM的API。
②大量使用了Java集合类,方便了Java开发人员。
【缺点】
①没有较好的灵活性。
②性能较差。

(4)DOM4J(Document Object Model for Java)
简单易用,采用Java集合框架,并完全支持DOM、SAX和JAXP
【优点】
①大量使用了Java集合类,方便Java开发人员,同时提供一些提高性能的替代方法。
②支持XPath。
③有很好的性能。
【缺点】
①大量使用了接口,API较为复杂。

(5)StAX(Streaming API for XML)
流模型中的拉模型分析方式。提供基于指针和基于迭代器两种方式的支持,JDK1.6新特性
【和推式解析相比的优点】
①在拉式解析中,事件是由解析应用产生的,因此拉式解析中向客户端提供的是解析规则,而不是解析器。
②同推式解析相比,拉式解析的代码更简单,而且不用那么多库。
③拉式解析客户端能够一次读取多个XML文件。
④拉式解析允许你过滤XML文件和跳过解析事件。
【简介】
StAX API的实现是使用了Java Web服务开发(JWSDP)1.6,并结合了Sun Java流式XML分析器(SJSXP)-它位于javax.xml.stream包中。XMLStreamReader接口用于分析一个XML文档,而XMLStreamWriter接口用于生成一个XML文档。XMLEventReader负责使用一个对象事件迭代子分析XML事件-这与XMLStreamReader所使用的光标机制形成对照。

3、总结解析pdm、ldm文件的代码

当文件很小的时候,用上面的多种方法,性能相差不多。但是当文件到达5M后,性能的差异就显示出来。

除了性能之外,还需要考虑具体的应用场景,选用不同的方案。

(1)DOM解析的方案,全部调整成(4)DOM4J方案。同样是10M的pdm文件,解析只要20秒,不是一个数量级的。核心源码如下:

public List<Table> loadAllTables(Element element1){
List<Table> allTables = new ArrayList<Table>();

//外键
List<Reference> allReferences = loadAllReferences(element1);

Element tableNode =(Element) element1.element("Tables");
//如果主题域下面没有表关联,则直接返回
if(tableNode==null){
return allTables;
}
for(Object t1:tableNode.elements("Table")){
Element t=(Element)t1;
Table table = new Table();
List<Column> allColumns = new ArrayList<Column>();
String tableId = t.attributeValue("Id");
String tableName = t.elementText("Name");
String tableCode = t.elementText("Code");
String tableComment = t.elementText("Comment");
table.setTableId(tableId);
table.setTableName(tableName);
table.setTableCode(tableCode);
table.setTableComment(tableComment);
//主键
List<String> allPKIds = loadAllPKIds(t);

//Column信息添加
Element columnNode = t.element("Columns");
for(Object col1:columnNode.elements()){
Element col=(Element)col1;
Column column = new Column();
String columnId = col.attributeValue("Id");
String columnName = col.elementText("Name");
String columnCode = col.elementText("Code");
String columnComment = col.elementText("Comment");
String dataType = col.elementText("DataType");
Long length =  NumberUtils.toLong(col.elementText("Length"));
Long precision = NumberUtils.toLong(col.elementText("Precision"));
//                Long mandatory = NumberUtils.toLong(col.elementText("LogicalAttribute.Mandatory"));
boolean pk = false;
//获取主键
if(allPKIds.contains(columnId)){
pk = true;
}
boolean fk = false;
//获取外键
for(Reference ref : allReferences){
if(columnId.equals(ref.getFKId())){
fk = true;
table.setParentTableId(ref.getParentTableId());
}
}
column.setColId(columnId);
column.setColName(columnName);
column.setColCode(columnCode);
column.setColComment(columnComment);
column.setDataType(dataType);
column.setLength(length);
column.setPrecision(precision);
column.setPK(pk);
column.setFK(fk);
allColumns.add(column);
}
table.setAllColumns(allColumns);
allTables.add(table);
}
return allTables;
}

欢迎大家一起讨论。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  pdm dom4j 提高性能