项目开发中涉及到对象与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);
}
}
转载于:https://blog.51cto.com/ccjava/1603756