JAXB 线程安全问题解决办法
项目开发中涉及到对象与XML的转换,考虑到代码的简洁性,一直在使用java内置的JAXB来完成这项任务
一直在用的方法:
static Map<String,Marshaller> mars static Map<String,Unmarshaller> umars
这样做的好处是对于相同的类名,不用重复创建marshaller。
但在一个银行项目上线中发现,经常会发生ArrayIndexOutOfBoundsException,经过google一番搜索,发现问题在于marshaller的marshal方法不是线程安全的,而JAXBContext.newInstance()是线程安全的。为了解决这一问题,需要将代码进行改造
为了尽量少的重复创建marshaller对象(创建marshaller对象的操作官方认为是比较耗CPU的)这里使用对象池的概念,开发包使用commons-pool,这里用到了KeyedObjectPool
static KeyedObjectPool marPool = new GenericKeyedObjectPool(new JaxbMarshallerFactory()); static KeyedObjectPool unmarPool = new GenericKeyedObjectPool(new JaxbUnmarshallerFactory()); class JaxbUnmarshallerFactory extends JaxbMarshallerFactory{ @Override public Object makeObject(Object key) throws Exception { Class<?> clazz = (Class<?>)key; if(contextMap.containsKey(key)){ JAXBContext context = JAXBContext.newInstance(clazz); contextMap.put(clazz, context); } return contextMap.get(clazz).createUnmarshaller(); } } class JaxbMarshallerFactory implements KeyedPoolableObjectFactory{ protected Map<Class<?>,JAXBContext> contextMap = new HashMap<Class<?>,JAXBContext>(); @Override public Object makeObject(Object key) throws Exception { Class<?> clazz = (Class<?>)key; if(!contextMap.containsKey(clazz)){ JAXBContext context = JAXBContext.newInstance(clazz); contextMap.put(clazz, context); } return contextMap.get(clazz).createMarshaller(); } @Override public void destroyObject(Object key, Object obj) throws Exception { contextMap.remove(key); } @Override public boolean validateObject(Object key, Object obj) { return true; } @Override public void activateObject(Object key, Object obj) throws Exception { // System.out.println("user "+Thread.currentThread()+" borrow "+obj.hashCode()); } @Override public void passivateObject(Object key, Object obj) throws Exception { // System.out.println("user "+Thread.currentThread()+" return "+obj.hashCode()); } }
这里定义了两个对象池工厂,分别保存marshaller和unmarshaller,感觉应该可以合并到一个工厂中,后面的实践中再加以改进。
在使用时应该注意borrowObject并使用完成后一定要记得returnObject,这样才能达到对象池的效果
public static void toOutputStream(Object o,OutputStream os) throws JAXBException{ Marshaller mar; try { // 从线程池中借出 mar = (Marshaller)marPool.borrowObject(o.getClass()); // 转换对象到XML mar.marshal(o, os); // 归还到对象池 marPool.returnObject(o.getClass(), mar); } catch (Exception e) { logger.error(e); } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。