用来记录一些原创性的总结
JAXBContext是使用JAXB的入口API,其主要持有Class对应的属性、方法等信息。实例化一个JAXBConext对象的成本是非常高的,但是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对象是线程不安全的,切勿进行重用。
以下是缓存JAXBContext和不缓存JAXBContext的情况下,对指定的对象进行10000次marshal的测试代码,缓存逻辑就是应用了上面的逻辑:
@Test
public void test() throws Exception {
int times = 10000;
User user = this.buildUser();
long nonCachedStart = System.currentTimeMillis();
for (int i=0; i<times; i++) {
JAXBContext jaxbContext = JAXBContext.newInstance(User.class, Role.class, SubRole.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(user, new StringWriter());
}
long nonCachedEnd = System.currentTimeMillis();
System.out.println("未缓存JAXBContext的耗时情况:" + (nonCachedEnd - nonCachedStart));
long cachedStart = System.currentTimeMillis();
for (int i=0; i<times; i++) {
JAXBContext jaxbContext = getJAXBContext(User.class, Role.class, SubRole.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(user, new StringWriter());
}
long cachedEnd = System.currentTimeMillis();
System.out.println("缓存了JAXBContext的耗时情况:" + (cachedEnd - cachedStart));
}
输出如下:
未缓存JAXBContext的耗时情况:31452
缓存了JAXBContext的耗时情况:95
很明显缓存JAXBContext的情况下性能能够得到显著的提高。
(注:本文由Elim写于2017年9月18日)