JAXBContext介绍及性能优化
摘要 本文主要介绍基于package创建JAXBContext,以及阐述JAXBContext存在的性能问题及其优化。
JAXBContext介绍
JAXBContext是我们在使用JAXB时的入口类,我们需要通过它的实例来建立XML和Java类之间的映射关系,需要通过它来创建用于转换Java对象到XML的Marshaller或是创建用于转换XML到Java对象的Unmarshaller。JAXBContext的实例需要通过JAXBContext.newInstance(..)方法产生,JAXBContext中定义了重载的5个newInstance(..)方法,定义如下:
public static JAXBContext newInstance( String contextPath );
public static JAXBContext newInstance( String contextPath, ClassLoader classLoader );
public static JAXBContext newInstance( String contextPath, ClassLoader classLoader, Map<String,?> properties );
public static JAXBContext newInstance( Class... classesToBeBound );
public static JAXBContext newInstance( Class[] classesToBeBound, Map<String,?> properties );
上述5个方法的区别在于是基于package的还是基于class的。contextPath用于指定需要绑定XML的Java类所在的包定义;classLoader用于指定使用的类加载器,未指定时将使用当前线程上下文所绑定的类加载器;properties用于指定JAXB实现者特定的属性;classesToBeBound用于直接指定需要绑定的Java类。
之前介绍的都是通过直接指定相关的Class作为入参的形式创建JAXBContext,如下所示:
JAXBContext jaxbContext = JAXBContext.newInstance(Response.class, Person.class);
这里着重介绍一下基于package创建JAXBContext的示例,如下所示:
JAXBContext jaxbContext = JAXBContext.newInstance("com.xxx.jaxb");
但是这时候并不是指定的包中所有的Class都会用来创建JAXBContext。按照JAXB的规范,我们需要在对应的包中创建一个jaxb.index文件,然后在其中指定创建JAXBContext时需要用到的Class,每个Class名称占一行,只需要写Class名称即可,如我们在创建JAXBContext时需要用到Response和Person类,我们就可以中jaxb.index文件中如下定义:
Response
Person
然后后续就可以用对应的JAXBContext来进行相应的Marshal和UnMarshal操作了。通过指定包名称创建JAXBContext的方式可以把程序中各种可能的场景中需要使用到的Class都初始化到一个JAXBContext中,这样可以保证这个JAXBContext可以在各种可能的场景下都能满足需求,JAXBContext的初始化是非常耗CPU的,重用JAXBContext有助于提升性能。另一方面我们如果在某一时刻调整使用的Class时可以不用修改源码,直接修改jaxb.index文件中定义的Class即可,这可比修改源码要简单的多。
为了保证文章的完整性,以下给出一个基于包名称初始化JAXBContext的完整示例。
@Test
public void testPerson() throws Exception {
Person person = new Person();
person.setId(1);
person.setName("张三");
Response response = this.newResponse(person);
JAXBContext jaxbContext = JAXBContext.newInstance("com.xxx.jaxb");
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(response, System.out);
}
private Response newResponse(Data realData) {
Response response = new Response();
response.setReturnCode(100);
response.setMessage("AAAA");
ResultData resultData = new ResultData();
resultData.setRealData(realData);
response.setResultData(resultData);
return response;
}
@XmlRootElement
public class Response {
private int returnCode;
private String message;
@XmlElement(name = "data")
private ResultData resultData;
//省略get/set
}
public class ResultData {
@XmlElementRef
private Data realData;
//省略get/set
}
public class Data {
}
@XmlRootElement(name="dept")
public class Person extends Data {
@XmlAttribute
private Integer id;
private String name;
//省略get/set
}
Response
Person
生成的XML如下:
<response>
<returnCode>100</returnCode>
<message>AAAA</message>
<data>
<dept id="1">
<name>张三</name>
</dept>
</data>
</response>
使用直接指定class创建JAXBContext的方式我们的代码可以是如下这样:
@Test
public void testPerson2() throws Exception {
Person person = new Person();
person.setId(1);
person.setName("张三");
Response response = this.newResponse(person);
JAXBContext jaxbContext = JAXBContext.newInstance(Person.class, Response.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(response, System.out);
}
通过package创建JAXBContext时也允许创建指定多个package,多个package之间通过英文冒号分隔,如下我们在创建JAXBContext时就同时指定了com.xxx.jaxb
和com.xxx.jaxb2
两个package。
JAXBContext jaxbContext = JAXBContext.newInstance("com.xxx.jaxb:com.xxx.jaxb2");
性能优化
每次在创建JAXBContext实例时,JAXBContext内部都需要维护好Java类和XML之间的映射关系,这个操作是十分消耗性能的。幸运的是JAXBContext是线程安全的,可以共享。关于JAXBContext存在的性能问题笔者准备了如下测试代码:
@Test
public void testPerformance() throws Exception {
for (int j=0; j<5; j++) {
int times = 100000;
long t1 = System.currentTimeMillis();
for (int i=0; i<times; i++) {
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(new Root(), new StringWriter());
}
long t2 = System.currentTimeMillis();
System.out.println("不共用JAXBContext耗时:" + (t2-t1) + "ms");
long t3 = System.currentTimeMillis();
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
for (int i=0; i<times; i++) {
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(new Root(), new StringWriter());
}
long t4 = System.currentTimeMillis();
System.out.println("共用JAXBContext耗时:" + (t4-t3) + "ms");
}
}
循环测试5次,每次分别在共享JAXBContext和不共享JAXBContext的情况下进行十万次marshal操作,由于这里我们不关心生成的XML,也避免输出到控制台或文件中的IO影响,这里每次都创建一个StringWriter,StringWriter是基于内存操作的。在笔者64位ubuntu17.10系统、处理器是Intel® Core™ i5-7500 CPU @ 3.40GHz × 4
、8GB内存的台式机下运行结果如下所示:
不共用JAXBContext耗时:17735ms
共用JAXBContext耗时:240ms
不共用JAXBContext耗时:16003ms
共用JAXBContext耗时:272ms
不共用JAXBContext耗时:15614ms
共用JAXBContext耗时:223ms
不共用JAXBContext耗时:15313ms
共用JAXBContext耗时:215ms
不共用JAXBContext耗时:15241ms
共用JAXBContext耗时:235ms
从测试结果我们可以很明显的看到共享JAXBContext的情况下性能有很明显的提升。共享JAXB时如果我们的所有的应用场景需要使用到的Class比较少时我们可以简单的在创建JAXBContext对象时传递所有需哟使用到的Class,把它保存起来之后都可以一直这样在我们的应用中使用它了。但是如果Class的定义在进行XML转换为Java对象时有冲突就不能这么做了,比如你有一个Person1和Person2两个Person类,它们映射的XML节点都是person,那么在把XML节点person转换为Java对象时是转换为Person1还是Person2呢?有这种场景获取Class相对较多时建议创建一个JaxbUtil工具类,所有的JAXBContext对象都由该工具类产生,在该工具类内部实现JAXBContext的重用,以下是一个简单的示例。
private static Map<List<Class<?>>, JAXBContext> jaxbContextMap = new ConcurrentHashMap<>();
public static JAXBContext getJAXBContext(Class<?> ...classes) throws JAXBException {
List<Class<?>> classList = new ArrayList<>(Arrays.asList(classes));
if (!jaxbContextMap.containsKey(classList)) {
JAXBContext jaxbContext = JAXBContext.newInstance(classes);
jaxbContextMap.put(classList, jaxbContext);
return jaxbContext;
}
return jaxbContextMap.get(classList);
}
需要注意的是虽然JAXBContext是线程安全的,但是它由它产生的Marshaller和Unmarshaller对象是线程不安全的,切勿进行重用。
相关推荐
在Java开发中,JAXB(Java Architecture for XML Binding)是一个用于将XML文档和Java对象之间进行绑定的技术。在处理XML文件时,特别是涉及到序列化和反序列化时,可能会遇到字符编码问题,即所谓的“乱码”。这个...
在Java开发中,JAXB(Java Architecture for XML Binding)是一个标准的API,用于将XML文档与Java对象之间进行互相转换。这个技术对于处理XML数据,尤其是解析和生成XML文档非常有用。当我们面临XML文档中存在嵌套子...
JAXB (Java Architecture for XML Binding) 是Java平台上的一个标准,用于将XML文档与Java对象之间进行绑定,实现XML数据的解析和序列化。在Java开发中,JAXB提供了一种方便的方式,允许开发者通过XML Schema (XSD) ...
使用java jdk的JAXB技术实现xml与java对象互相转化...•JAXBContext类,是应用的入口,用于管理XML/Java绑定信息。 •Marshaller接口,将Java对象序列化为XML数据。 •Unmarshaller接口,将XML数据反序列化为Java对象。
jaxb-impl-2.1.13.jar
JAXBContext 生成 XML 文件或 Java 类对象转换注解 JAXB(Java API for XML Binding)是一种将 Java 对象与 XML 进行转换的技术。JAXB 提供了一个快速便捷的方式将 Java 对象与 XML 进行转换。在 JAX-WS(Java 的 ...
2. **性能**:由于JAXB是Java平台的标准部分,它通常比第三方库更快,因为它可以利用JVM的优化。 3. **自动类型检查**:在序列化和反序列化过程中,JAXB会自动执行类型检查,确保数据一致性。 4. **与XML Schema集成...
1. `jaxb-api-2.2.7.jar`:这是JAXB的主要API,提供了基本的接口和类,如`javax.xml.bind.JAXBContext`和`javax.xml.bind.Marshaller`,用于实现XML和Java对象的转换。`JAXBContext`是整个转换过程的核心,负责创建...
它提供了必要的接口和类,如`javax.xml.bind.JAXBContext`, `Unmarshaller`, `Unmarshaller`, 和 `Validator`等,用于实现XML到Java对象的编组(marshalling)和反编组(unmarshalling)。API本身不包含具体的实现,...
当我们需要处理XML文件,比如从XML中提取数据时,JAXB(Java Architecture for XML Binding)是一个强大的工具。本教程将详细解释如何在Idea中利用JAXB来读取XML文件中的数据。 JAXB是Java标准API,它提供了将Java...
6. **性能优化**:JAXB2.1在性能方面进行了优化,提升了XML文档的解析速度和内存使用效率。 **二、JAXB API** `jaxb-api.jar` 包含了JAXB的主要API,其中包括核心的接口和类,如`javax.xml.bind.JAXBContext`,`...
2. **设置JAXB上下文**:使用`JAXBContext`来获取Java类型和XML之间的映射信息。这一步通常需要传递Java类的Class对象作为参数。 3. **序列化(Marshalling)**:创建`Marshaller`实例,并调用其`marshal()`方法将...
1. **Java SE 9+支持**:JAXB 2.3.0开始支持Java 9及其后续版本,这包括模块化系统(Jigsaw)的集成。 2. **API增强**:可能包含了新的API接口或方法,以提供更丰富的功能和更好的用户体验。 3. **性能优化**:可能...
三、JAXB的基本使用 1. 定义Java类:首先,我们需要定义一个Java类,该类的属性对应XML文档中的元素和属性。JAXB会自动为这些属性生成getter和setter方法。 2. 创建JAXBContext:这是JAXB的核心,负责管理和控制XML...
如何更好地jaxb使用如何更好地jaxb使用如何更好地jaxb使用如何更好地jaxb使用
JAXB(Java Architecture for XML Binding)是Java平台上的一个标准,它提供了一种在Java对象和XML文档之间进行映射的机制。Eclipse作为一款强大的Java集成开发环境,为开发者提供了丰富的插件支持,其中包括JAXB的...
JAXBContext是JAXB框架的核心,它扮演着一个工厂的角色,负责创建Unmarshaller(用于从XML到Java对象的转换)和Marshaller(用于从Java对象到XML的转换)。在这个"JAXBContext测试Java对象与xml的相互转换Demo"中,...
接着,可以使用`JAXBContext`来创建一个上下文,该上下文知道如何处理这些Java类。之后,`Marshaller`对象用于将Java对象序列化为XML,而`Unmarshaller`则用于从XML文档反序列化回Java对象。 在实际应用中,JAXB...
JAXB2,全称为Java Architecture for XML Binding 2,是Java平台上的一个标准技术,用于在XML和Java对象之间进行绑定。它允许开发者通过简单的API将XML文档转换为Java对象,反之亦然,大大简化了XML数据处理。JAXB2...
标题中的"jaxb-impl-2.3.0、jaxb-core-2.3.0、jaxb-api-2.3.0"是JAXB的不同组件版本号,它们在处理XML到Java对象之间的转换时起到关键作用。在描述中提到的“Maven项目中缺少jaxb-api的异常报错”,通常指的是在运行...