Mule ESB异步场景下JAXB转换出现ConcurrentModificationException问题
Mule 3.9.x异步块中JAXB对象转XML触发ConcurrentModificationException的解决方案
问题场景
在Mule 3.9.x社区版环境下,将jaxb-object-to-xml-transformer组件放入<async>异步块执行对象转XML操作时,触发java.util.ConcurrentModificationException异常。同步场景下该功能运行正常,升级至Mule 3.9.5后问题仍未解决,需在不升级到Mule 4+的前提下修复此问题。
异常栈信息
Message : null (java.util.ConcurrentModificationException) Element : /test/processors/0 @ test-masked:masked.xml:685 (JAXB Object to JMSMessage (XML string)) -------------------------------------------------------------------------------- Exception stack is: null (java.util.ConcurrentModificationException) (org.mule.api.transformer.TransformerException) java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) java.util.ArrayList$Itr.next(ArrayList.java:851) com.sun.xml.bind.v2.runtime.reflect.Lister$CollectionLister$1.next(Lister.java:284) com.sun.xml.bind.v2.runtime.property.ArrayElementProperty.serializeListBody(ArrayElementProperty.java:135) com.sun.xml.bind.v2.runtime.property.ArrayERProperty.serializeBody(ArrayERProperty.java:155) com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340) com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696) com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:152) com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340) com.sun.xml.bind.v2.runtime.XMLSerializer.childAsXsiType(XMLSerializer.java:696) com.sun.xml.bind.v2.runtime.property.SingleElementNodeProperty.serializeBody(SingleElementNodeProperty.java:152) com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeBody(ClassBeanInfoImpl.java:340) com.sun.xml.bind.v2.runtime.XMLSerializer.childAsSoleContent(XMLSerializer.java:593) com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:324) com.sun.xml.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:494) com.sun.xml.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:315) com.sun.xml.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:244) javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:116) org.mule.module.xml.transformer.jaxb.JAXBMarshallerTransformer.doTransform(JAXBMarshallerTransformer.java:77) org.mule.transformer.AbstractTransformer.transform(AbstractTransformer.java:415) org.mule.transformer.AbstractTransformer.transform(AbstractTransformer.java:366) (40 more...)
异步配置代码
<async> <mulexml:jaxb-object-to-xml-transformer returnClass="java.lang.String" mimeType="text/xml" jaxbContext-ref="JAXB_Context_Update_Journey"/> <logger message="#[message:correlationId] | pushing to cache.inbox -payload - #[payload]" level="INFO" category="update cache" /> </async>
原因分析
从异常栈可以看出,JAXB在序列化ArrayList集合时,迭代器检测到集合正在被并发修改。根本原因是:
- Mule的
<async>块会共享原消息对象,若原线程在异步线程执行JAXB序列化的同时,继续修改payload中的集合属性,就会触发ConcurrentModificationException。 - 同步场景下是单线程执行,不存在并发修改问题,因此运行正常。
解决方案
1. 进入异步块前深拷贝对象
确保异步块处理的是对象的独立副本,彻底隔离原线程的修改操作。可以使用Apache Commons Lang的序列化工具实现深拷贝,示例如下:
<!-- 在async块前添加深拷贝转换器 --> <scripting:transformer doc:name="Deep Copy Payload"> <scripting:script engine="Groovy"> import org.apache.commons.lang3.SerializationUtils // 需确保JAXB注解的类实现Serializable接口 def copiedPayload = SerializationUtils.clone(payload) return copiedPayload </scripting:script> </scripting:transformer> <async> <mulexml:jaxb-object-to-xml-transformer returnClass="java.lang.String" mimeType="text/xml" jaxbContext-ref="JAXB_Context_Update_Journey"/> <logger message="#[message:correlationId] | pushing to cache.inbox -payload - #[payload]" level="INFO" category="update cache" /> </async>
如果目标类无法实现Serializable,可以手动创建对象副本,逐个复制属性(集合类型需重新创建并复制元素),示例Groovy代码:
// 假设原对象是Journey类,包含List<Step> steps属性 def original = payload def copied = new Journey() copied.setId(original.getId()) // 复制集合:创建新ArrayList并添加所有元素 copied.setSteps(new ArrayList<>(original.getSteps())) // 复制其他属性... return copied
2. 禁止原线程修改异步块共享的对象
如果业务允许,确保进入<async>块后,原线程不再修改payload中的任何对象属性(尤其是集合类型)。这种方式无需修改代码,但需要严格控制业务逻辑的执行顺序,避免并发修改。
3. 验证JAXB上下文配置
虽然JAXBContext本身是线程安全的,但需确认Mule配置的jaxbContext-ref是否正确初始化。若使用自定义JAXBContext,确保其配置支持并发场景,但此方案仅解决上下文本身的线程安全问题,无法解决对象被并发修改的核心问题,因此仅作为辅助验证手段。
内容的提问来源于stack exchange,提问作者Mahesh A R
相关产品推荐
相关产品推荐

