Как повысить производительность приложения, использующего операцию 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)