Статьи

При использовании JAXB

Немного примеров показывают это, но то, как вы используете JAXB в своем приложении, может сильно повлиять на производительность (и использование памяти).

Пример

В этом посте я буду использовать пример объекта с именем Membership который выглядит примерно так:

используя JAXB

Мы будем маршалировать и демаршировать этот объект в и из 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";
  private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";

(Полный пример здесь )

Получить все

Вы можете получить все «хорошее» в простой библиотеке:

Используя это в вашем коде

(См. 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, являются их собственными.