我尝试将一些基于Apache digester的XML序列化代码迁移到JAXB,结果很差。对于这种设计模式的最佳实践是否有一些建议(或放弃使用这个设计模式的JAXB ......)?
XML严重依赖于接口和反射声明。
<someContainer>
<someChild class="foo.Class1">
</someChild>
</someContainer>
我使用带有此解组代码的适配器
解决了间接问题public ResultType unmarshal(Object object) throws Exception {
Element element = (Element) object;
String classname = element.getAttribute("class");
Class clazz = Class.forName(classname);
JAXBContext jc = getContext(clazz);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Object result = unmarshaller.unmarshal(element, clazz);
if (result instanceof JAXBElement) {
return (ResultType) ((JAXBElement) result).getValue();
}
return (ResultType) result;
}
好吧,即使使用JAXBContext缓存,这是到目前为止优于基于消化器的代码(对于这一点没有确切的安慰,可以说大约50到100次)。实际性能损失的主要原因似乎是unmarshal的“元素”参数。大部分时间用于创建重新转换已经解析的元素所需的新DocumentBuilder环境
有什么建议吗?
答案 0 :(得分:4)
我做了很多像这样的事情并且不能抱怨JAXB表现不佳,这在我的案例中是首要任务。在相当慢的服务器上,5kb有效负载完全相同的任务不超过3-4毫秒。至于缓存,我通常为你的情况采用编组/解组的以下双向数据结构:
Map<String, MarshallData> marshalCache;
public ResultType unmarshal(Object object) throws Exception {
Element element = (Element) object;
MarshallData md = marshalCache.get(element.getAttribute("class"));
Object result = md.unmarshaller.unmarshal(element);
if (result instanceof JAXBElement) {
return (ResultType) ((JAXBElement) result).getValue();
}
return (ResultType) result;
}
public void registerMarshallData(Class clazz) throws Exception {
JAXBContext jbc = JAXBContext.newInstance(clazz); // or get it somewhere else if needed
MarshallData mdata = new MarshallData(jbc.createMarshaller(), jbc.createUnmarshaller());
marshalCache.put(clazz.getName(), mdata);
}
class MarshallData {
private Unmarshaller unmarshaller;
private Marshaller marshaller;
protected MarshallData(Marshaller marshaller, Unmarshaller unmarshaller) {
this.marshaller = marshaller;
this.unmarshaller = unmarshaller;
}
}
答案 1 :(得分:3)
好吧,我添加这个以供其他人参考,想知道他们是否需要放弃JAXB。
添加
-Djavax.xml.parsers.DocumentBuilderFactory=com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderFactoryImpl
完成了这项工作。现在的表现具有相同的数量级。看来我们有一个普通的类路径问题。在 large 类路径中,(未缓存的)DocumentBuilderFactory所需的服务提供者查找是导致性能不佳的关键因素。为VM提供一个已知的实现以避免搜索....
我在“随机”分析之后尝试了这个(按下暂停时按:-)总是以这样的搜索顺序结束:
Thread [main] (Suspended)
owns: VirtualKeyStoreHolder (id=417)
owns: CertificateStoreEnvironment (id=418)
owns: ManagedCertificateProvider (id=419)
owns: CertificateStoreEnvironment$1 (id=420)
WinNTFileSystem.getBooleanAttributes(File) line: not available [native method]
File.exists() line: 733
URLClassPath$FileLoader.getResource(String, boolean) line: 999
URLClassPath$FileLoader.findResource(String, boolean) line: 966
URLClassPath.findResource(String, boolean) line: 146
URLClassLoader$2.run() line: 385
AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]
Launcher$AppClassLoader(URLClassLoader).findResource(String) line: 382
Launcher$AppClassLoader(ClassLoader).getResource(String) line: 1003
Launcher$AppClassLoader(ClassLoader).getResourceAsStream(String) line: 1193
SecuritySupport$4.run() line: 96
AccessController.doPrivileged(PrivilegedAction<T>) line: not available [native method]
SecuritySupport.getResourceAsStream(ClassLoader, String) line: 89
FactoryFinder.findJarServiceProvider(String) line: 250
FactoryFinder.find(String, String) line: 223
DocumentBuilderFactory.newInstance() line: 123
TransformerIdentityImpl.createResultContentHandler(Result) line: 215
TransformerIdentityImpl.setDocumentLocator(Locator) line: 881
DomLoader$State.<init>(DomLoader, UnmarshallingContext) line: 78
DomLoader<ResultT>.startElement(UnmarshallingContext$State, TagName) line: 113
XsiTypeLoader.startElement(UnmarshallingContext$State, TagName) line: 76
UnmarshallingContext._startElement(TagName) line: 481
UnmarshallingContext.startElement(TagName) line: 459
SAXConnector.startElement(String, String, String, Attributes) line: 148
SAXParserImpl$JAXPSAXParser(AbstractSAXParser).startElement(QName, XMLAttributes, Augmentations) line: 501
XMLNSDocumentScannerImpl.scanStartElement() line: 400
XMLNSDocumentScannerImpl$NSContentDriver(XMLDocumentFragmentScannerImpl$FragmentContentDriver).next() line: 2755
XMLNSDocumentScannerImpl(XMLDocumentScannerImpl).next() line: 648
XMLNSDocumentScannerImpl.next() line: 140
XMLNSDocumentScannerImpl(XMLDocumentFragmentScannerImpl).scanDocument(boolean) line: 511
XIncludeAwareParserConfiguration(XML11Configuration).parse(boolean) line: 808
XIncludeAwareParserConfiguration(XML11Configuration).parse(XMLInputSource) line: 737
SAXParserImpl$JAXPSAXParser(XMLParser).parse(XMLInputSource) line: 119
SAXParserImpl$JAXPSAXParser(AbstractSAXParser).parse(InputSource) line: 1205
SAXParserImpl$JAXPSAXParser.parse(InputSource) line: 522
UnmarshallerImpl.unmarshal0(XMLReader, InputSource, JaxBeanInfo) line: 211
UnmarshallerImpl.unmarshal(XMLReader, InputSource) line: 184
UnmarshallerImpl(AbstractUnmarshallerImpl).unmarshal(InputSource) line: 137
UnmarshallerImpl(AbstractUnmarshallerImpl).unmarshal(InputStream) line: 184
VirtualKeyStoreTools.createVirtualKeyStore(InputStream) line: 54
... more to come
由于有待处理的赏金,我会将此提供给@Osw(当可以应用赏金时)作为答案“是的,你可以JAXB”是正确的。我认为使用SAX解决方案或与蒸煮器保持更长时间之间的微小性能差异是不合理的。另外,缓存JAXBContext似乎是明智的,我无法告诉缓存unmarshaller上下文 - 可能有人添加了有关此信息。
感谢您的支持。
修改
根据@Osw的要求,这里有一些(令人失望的)总体表现数据。
我直接在解析过程中为旧应用程序和新应用程序做了一些脏工具。虽然加载一堆文件的交互式应用程序的数字是“可接受的”,但我必须承认消化器的速度仍然超过2 *。
JAXB实现已经包含了unmarshaller的缓存,因此完成了“开箱即用”的优化。这给我留下了一个功能性的应用程序,迫切需要一些更多的分析。完成后我会回来,会出现一些普遍感兴趣的有趣技巧。