码迷,mamicode.com
首页 > 编程语言 > 详细

JAXB 线程安全问题解决办法

时间:2015-01-14 18:30:02      阅读:668      评论:0      收藏:0      [点我收藏+]

标签:jaxb   thread safe   

项目开发中涉及到对象与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);
    }    
}


JAXB 线程安全问题解决办法

标签:jaxb   thread safe   

原文地址:http://ccjava.blog.51cto.com/8646011/1603756

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!