[Web Service] Rop在进行响应或输入的序列化时存在线程安全问题

来源:互联网 发布:nginx 打印php的错误 编辑:程序博客网 时间:2024/04/27 14:03
stamen 2012-05-17
    由于我原来的Marshaller是一个RopResponse对应一个实例,也即一个RopResponse类是共享一个单实例的Marshaller。当时,我认为Marshaller是线程安全的,但是经过测试,Marshaller是非线程安全的:
    可以看这篇文章:
http://jaxb.java.net/guide/Performance_and_thread_safety.html
    我马上会修复这个BUG的。
引用收藏
stamen 2012-05-18
RopResponseMarshaller的实现类包括以下两个:
  • JacksonJsonRopResponseMarshaller:内部使用org.codehaus.jackson.map.ObjectMapper进行JSON序列化
  • JaxbXmlRopResponseMarshaller:内部使用javax.xml.bind.Marshaller进行XML序列化


org.codehaus.jackson.map.ObjectMapper是线程安全的(参见:http://wiki.fasterxml.com/JacksonFAQThreadSafety),而javax.xml.bind.Marshaller是非线程安全的。原来的Rop对ObjectMapper和Marshaller都采用了单实例的方式,因此存在线程安全的问题。

关于javax.xml.bind.Marshaller非线程安全的说明参见:http://jaxb.java.net/guide/Performance_and_thread_safety.html

不但javax.xml.bind.Marshaller是非线程安全的,Spring OXM的Marshaller也是非线程安全的,参见其javadoc的说明:
引用

createMarshaller

protected Marshaller createMarshaller()
Return a newly created JAXB marshaller. JAXB marshallers are not necessarily thread safe.


原来的JaxbXmlRopResponseMarshaller:
Java代码  收藏代码
  1. public class JaxbXmlRopResponseMarshaller implements RopResponseMarshaller {  
  2.   
  3.     private static Map<Class, Marshaller> marshallerMap = new HashMap<Class, Marshaller>();  
  4.   
  5.     public void marshaller(RopResponse response, OutputStream outputStream) {  
  6.         try {  
  7.             Marshaller m = getMarshaller(response);  
  8.             m.marshal(response, outputStream);  
  9.         } catch (JAXBException e) {  
  10.             throw new RopException(e);  
  11.         }  
  12.     }  
  13.   
  14.     private Marshaller getMarshaller(RopResponse response) throws JAXBException {  
  15.         if (!marshallerMap.containsKey(response.getClass())) {  
  16.             JAXBContext context = JAXBContext.newInstance(response.getClass());  
  17.             Marshaller marshaller = context.createMarshaller();//Marshaller是非线程安全的,不能多线程共用 !!!!  
  18.             marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);  
  19.             marshaller.setProperty(Marshaller.);  
  20.             marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");  
  21.             marshallerMap.put(response.getClass(), marshaller);  
  22.         }  
  23.         return marshallerMap.get(response.getClass());  
  24.     }  
  25. }  

更改为:
Java代码  收藏代码
  1. public class JaxbXmlRopResponseMarshaller implements RopResponseMarshaller {  
  2.   
  3.     private static Map<Class, JAXBContext> jaxbContextHashMap = new ConcurrentHashMap<Class, JAXBContext>();  
  4.   
  5.     public void marshaller(RopResponse response, OutputStream outputStream) {  
  6.         try {  
  7.             Marshaller m = buildMarshaller(response);  
  8.             m.marshal(response, outputStream);  
  9.         } catch (JAXBException e) {  
  10.             throw new RopException(e);  
  11.         }  
  12.     }  
  13.   
  14.   
  15.     public Marshaller buildMarshaller(RopResponse response) throws JAXBException {  
  16.         if (!jaxbContextHashMap.containsKey(response.getClass())) {  
  17.             JAXBContext context = JAXBContext.newInstance(response.getClass());//JAXBContext是线程安全的  
  18.             jaxbContextHashMap.put(response.getClass(), context);  
  19.         }  
  20.         JAXBContext context = jaxbContextHashMap.get(response.getClass());  
  21.         Marshaller marshaller = context.createMarshaller();//每次创建一个新的Marshaller  
  22.         marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);  
  23.         marshaller.setProperty(Marshaller.JAXB_ENCODING, "utf-8");  
  24.         return marshaller;  
  25.     }  
  26. }  


其实,根据测试创建Marshaller的时间很短,只有1毫秒左右,而真正慢的是创建JAXBContext,大家100毫秒左右。所以,这样改后,对Rop序列化的性能不会有什么影响,因为JAXBContext是共享的。

已经同步到git中。
原创粉丝点击