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);
    }    
}
时间: 2024-10-13 22:33:00

JAXB 线程安全问题解决办法的相关文章

android使用友盟实现第三方登录、分享以及微信回调无反应问题解决办法

        Leaning_wk每一次的进步都会拉近与成功的距离! 帐号设置退出   关闭 qq_15855289的博客 目录视图 摘要视图 订阅 异步赠书:Kotlin领衔10本好书      免费直播:AI时代,机器学习如何入门?      程序员8月书讯      每周荐书:Java Web.Python极客编程(评论送书) android使用友盟实现第三方登录.分享以及微信回调无反应问题解决办法 标签: android友盟第三方登录分享微信登录回调问题 2017-02-10 16:2

centos7 初次开机问题解决办法

centos7初次开机问题解决办法

带有ListView的界面无法通过手势左右滑动切换界面问题解决办法

问题描述: 在做OnGestureListener滑动切换窗口的时候,会遇到这样的问题.就是当界面中含有ListView的时候,OnGestureListener的左右触屏滑动就被ListView自己吃掉了. 问题分析: 在Android系统中,事件的分发和响应都按照一定的优先级仅仅有条的进行着.如果Activity中包含ListView那么系统的onTouchEvent事件会优先分发给ListView去处理,这时ListView的OnItemClickListener监听器会优先响应onTou

zabbix导入模版问题解决办法

当我们监控一些东西需要使用zabbix模版的时候,而模版没有怎么办?最简单的方法就是导入模版了 模版可以去https://www.zabbix.org/wiki/Zabbix_Templates/Official_Templates这里下载 而在导入的时候会报一些错误,下面给出导入vmware template报错的解决办法: 首先检查zabbix中是不是有模版对应的value map,没有的话导入的时候就报错啦. 手工创建value map: zabbix:在Administrator->ge

***微信 该连接无法访问问题解决办法

微信开发是提示: 该连接无法访问问题解决办法 解决: 1.第一个修改接口权限中的域名为你的业务服务器的域名 2.请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限. 主要涉及的是 网页授权获取用户基本信息 http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html 如果用户在微信客户端中访问第三方网页,公众号可以通过微信网页授权机制,来获取用户基本信息,进而实现业务逻辑. 关于网页授权回调域名的说明

vmware虚拟机克隆CentOS7 出现的网络问题解决办法

http://www.bubuko.com/infodetail-1483490.html(转) vmware虚拟机克隆CentOS7 出现的网络问题解决办法 时间:2016-04-02 07:17:00                         阅读:578                         评论:0                         收藏:0                         [点我收藏+] 1.删除/etc/sysconfig/network

eclipse平台 android项目前显示红色叉号 android level-19 4.4平台导入项目 问题解决办法

android level-19  4.4平台导入项目 项目前显示红色叉号  问题解决办法 android level-19  4.4平台导入项目 项目前显示红色叉号,检查项目中文件,文件前没有叉号,分析是项目导入的问题,或者是lib库配置的问题. 1.用eclipse建立一个简单的android项目, HelloWorld: 2.选择HelloWorld项目,鼠标右键选择Build Path-Configure Build Path 对比发现,没有勾选 Android 4.4. 2.选择导入的

Gitbook 生成 pdf 中文字体错乱问题解决办法

Gitbook 生成 pdf 中文字体错乱问题解决办法 用过 Gitbook 的都知道, Gitbook 会自动生成 pdf 以提供下载, 但十分遗憾的是自动生成的 pdf 对中文的支持并不好, 经常出现字体不一致的现象, 影响阅读, 强迫症更是难以忍受. 示例: 下面针对这一问题提供简单的解决办法: 本地命令行生成 pdf 文件. 当然这种方法有一定局限性, 你需要找到托管在 github 对应的源码仓库且转换过程中不出错. (由于水平有限未能解决在线生成的pdf中文字体错乱问题, 见谅. 也

有关Transaction not successfully started问题解决办法

我的项目配置:struts2+hibernate3.3+spring3.2.5 主要问题:在进行更新和提交操作时出现以下异常 org.springframework.transaction.TransactionSystemException: Could not commit Hibernate transaction; nested exception is org.hibernate.TransactionException: Transaction not successfully st