Немного примеров показывают это, но то, как вы используете JAXB в своем приложении, может сильно повлиять на производительность (и использование памяти).
Пример
В этом посте я буду использовать пример объекта с именем Membership
который выглядит примерно так:
Мы будем маршалировать и демаршировать этот объект в и из XML с помощью JAXB.
Создать контекст в статическом блоке (или хотя бы один раз)
Самая большая ошибка, которую я обычно вижу, заключается в том, что контекст JAXB создается при каждом запросе:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
public String marshal(Membership membership){ StringWriter stringWriter = new StringWriter(); try { JAXBContext context = JAXBContext.newInstance(Membership. class ); Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(membership, stringWriter); String xml = stringWriter.toString(); stringWriter.close(); return xml; } catch (JAXBException | IOException ex) { throw new RuntimeException(ex); } } public Membership unmarshal(String xml) { try { JAXBContext context = JAXBContext.newInstance(Membership. class ); Unmarshaller u = context.createUnmarshaller(); return (Membership)u.unmarshal( new StringReader(xml)); } catch (JAXBException ex) { throw new RuntimeException(ex); } } |
(Также см. Пример кода здесь )
Проблема здесь заключается в методе JAXBContext.newInstance
который создает контекст. Контекст изменяется только в случае изменения структуры объекта, и это происходит только при изменении кода, поэтому мы можем безопасно сделать это только один раз, поэтому измените его, создав его в статическом блоке, например так:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
public String marshal(Membership memberships){ StringWriter stringWriter = new StringWriter(); try { Marshaller m = context.createMarshaller(); m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE); m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); m.marshal(memberships, stringWriter); String xml = stringWriter.toString(); stringWriter.close(); return xml; } catch (JAXBException | IOException ex) { throw new RuntimeException(ex); } } public Membership unmarshal(String xml) { try { Unmarshaller u = context.createUnmarshaller(); return (Membership)u.unmarshal( new StringReader(xml)); } catch (JAXBException ex) { throw new RuntimeException(ex); } } private static JAXBContext context; static { try { context = JAXBContext.newInstance(Membership. class ); } catch (JAXBException ex) { throw new RuntimeException(ex); } } |
(Также см. Пример кода здесь )
Итак, давайте посмотрим, что это меняет.
Пакетный пример.
Если мы конвертируем 10000 объектов в и из XML в цикле (по одному за раз), это будет результат:
1
2
3
4
|
Testing 10000 with Bad util Marshal took: 10804 ms Unmarshal took: 13762 ms |
а затем со статическим блоком:
1
2
3
4
|
Testing 10000 with Good util Marshal took: 90 ms Unmarshal took: 428 ms |
Это маршалинг в 120 раз, а маршаллинг в 32 раза быстрее!
(Полный пример здесь )
Пример параллелизма.
Точно так же при выполнении нескольких параллельных запросов вы должны увидеть одинаковые результаты. Поэтому, когда мы развернем это на каком-нибудь сервере (в моем примере это thorntail ) и выставим конечную точку REST маршалу и демаршалу, мы сможем использовать что-то вроде siege для генерации параллельного трафика на сервер:
Вывод плохого примера:
01
02
03
04
05
06
07
08
09
10
11
12
|
Transactions: 255 hits Availability: 100.00 % Elapsed time: 7.91 secs Data transferred: 0.54 MB Response time: 5.13 secs Transaction rate: 32.24 trans/sec Throughput: 0.07 MB/sec Concurrency: 165.52 Successful transactions: 255 Failed transactions: 0 Longest transaction: 6.88 Shortest transaction: 3.47 |
Вывод хорошего примера:
01
02
03
04
05
06
07
08
09
10
11
12
|
Transactions: 255 hits Availability: 100.00 % Elapsed time: 1.80 secs Data transferred: 0.53 MB Response time: 0.52 secs Transaction rate: 141.67 trans/sec Throughput: 0.30 MB/sec Concurrency: 73.12 Successful transactions: 255 Failed transactions: 0 Longest transaction: 0.78 Shortest transaction: 0.05 |
Обратите внимание на разницу значений «параллелизма» («Параллельность» — это среднее количество одновременных подключений, которое увеличивается с уменьшением производительности сервера).
(Полный пример здесь )
Когда файл очень очень большой.
Если ваш входной файл слишком большой, вы можете получить исключение java.lang.OutOfMemoryError
.
Чтобы убедиться, что вы можете эффективно обрабатывать большие файлы, вы можете убедиться, что вы используете SAX Parser при создании ввода:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public Membership unmarshalWithSAX(InputStream xml){ try { InputSource inputSource = new InputSource(xml); SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setNamespaceAware( true ); spf.setValidating( true ); SAXParser saxParser = spf.newSAXParser(); saxParser.setProperty(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); XMLReader xmlReader = saxParser.getXMLReader(); SAXSource source = new SAXSource(xmlReader, inputSource); Unmarshaller u = context.createUnmarshaller(); return (Membership)u.unmarshal(source); } catch (ParserConfigurationException | SAXException | JAXBException ex) { throw new RuntimeException(ex); } } private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage" ; |
(Полный пример здесь )
Получить все
Вы можете получить все «хорошее» в простой библиотеке:
Используя это в вашем коде
(См. Https://github.com/phillip-kruger/jaxb-lib )
1
2
3
4
5
|
<dependency> <groupId>com.github.phillip-kruger.jaxb-library</groupId> <artifactId>jaxb-lib</artifactId> <version> 1.0 . 0 </version> </dependency> |
маршал
1
2
|
JaxbUtil jaxbUtil = new JaxbUtil(); byte [] xml = jaxbUtil.marshal(myJAXBObject); |
распаковать
1
2
|
JaxbUtil jaxbUtil = new JaxbUtil(); MyJAXBObject myJAXBObject = jaxbUtil.unmarshal(MyJAXBObject. class ,xml); |
Получение XSD для объекта JAXB
1
2
|
XsdUtil xsdUtil = new XsdUtil(); String xsd = xsdUtil.getXsd(MyJAXBObject. class ); |
Опубликовано на Java Code Geeks с разрешения Филиппа Крюгера, партнера нашей программы JCG . Смотрите оригинальную статью здесь: При использовании JAXB… Мнения, высказанные участниками Java Code Geeks, являются их собственными. |