Как повысить производительность приложения, использующего операцию JAXBContext.newInstance?

Я использую операцию JAXBContext.newInstance в своем веб-приложении на основе JBoss. Эта операция, как я понимаю, очень тяжелая. Мне нужны только два уникальных экземпляра класса Marshaller.

Мое первоначальное предложение состоит в том, чтобы иметь статический блок инициализатора, который будет инициализировать эти два экземпляра только один раз при загрузке класса:

public class MyWebApp {
    private static Marshaller requestMarshaller;
    private static Marshaller responseMarshaller;

    static {
        try {
            // one time instance creation
            requestMarshaller = JAXBContext.newInstance(Request.class).createMarshaller();
            responseMarshaller = JAXBContext.newInstance(Response.class).createMarshaller();
        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

    private void doSomething() {
            requestMarshaller.marshall(...);
            responseMarshaller.marshall(...);
            ...
    }

}

Если это разумное решение, я думаю, что я отвечу на свой вопрос, но я хотел бы знать, правильно ли это сделать?

Ответы

Ответ 1

Реализация JAXB (Metro, EclipseLink MOXy, Apache JaxMe и т.д.) обычно инициализирует свои метаданные во время вызова JAXBContext.newInstance. Все инструменты OXM должны инициализировать метаданные сопоставления в какой-то момент и попытаться свести к минимуму стоимость этой операции. Поскольку это невозможно сделать с нулевой стоимостью, лучше всего сделать это только один раз. Экземпляры JAXBContext являются потокобезопасными, поэтому да, вам нужно только создать его один раз.

Из спецификации JAXB 2.2, раздел 4.2 Контекст JAXB:

Чтобы избежать накладных расходов, связанных с создание экземпляра JAXBContext, Приложение JAXB рекомендуется повторно использовать экземпляр JAXBContext. реализация абстрактного класса JAXBContext должен быть поточно-безопасный, таким образом, несколько потоков в приложение может совместно использовать одно и то же Экземпляр JAXBContext.

Экземпляры Marshaller и Unmarshaller не являются потокобезопасными и не должны делиться между потоками, они легки для создания.

Ответ 2

JAXBContext всегда должен быть статическим, это потокобезопасно.

Маршаллеры и Unmarshallers дешевы, а не потокобезопасны. Вы должны создать один раз JAXBContext и создать marshallers/unmarshallers для каждой операции

public class MyWebApp {
    private static JAXBContext jaxbContext;

    static {
        try {
            // one time instance creation
            jaxbContext = JAXBContext.newInstance(Request.class, Response.class);
        } catch (JAXBException e) {
            throw new IllegalStateException(e);
        }
    }

    private void doSomething() {                
            jaxbContext.createMarshaller().marshall(...);
            ...
    }

}

Используйте тот же маршаллер для сортировки всех (добавьте все классы при создании контекста).

Ответ 3

Недавно я провел некоторое тестирование производительности с помощью JAXBContext.newInstance, и результат был задокументирован здесь.

http://app-inf.blogspot.com/2012/10/performance-tuning-logging-right-way.html

При вызове одним потоком, используя довольно большую схему с ~ 195 классами, она достигла ~ 400 мс. Когда вы вызывали 20 потоков одновременно, это вызывало утверждения cpu и занимало до 5000 мс для завершения. Создание сериализации маршаллера и объекта маленького объекта слишком ~ 14 мс.

Ответ 4

Можно использовать javax.xml.bind.JAXB. Он имеет прямое маршала и немаршальные методы. Поэтому вам не нужно беспокоиться о создании экземпляра JAXB.

например. JAXB.unmarshal(inputStream/inputFile, outputClassExpected) или JAXB.marshal(jaxbObject, xmlOutputFile/xmlOutputStream)