Elim的博客

用来记录一些原创性的总结


Elim

JAXB之调优JAXBContext

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日)