高效的XML解析与组装-fasterxml
写在前面
最近公司有个需求,需要对接某甲方的老业务系统,传输过来的是ESB报文,也就是XML格式的,响应回去的也是XML报文。虽然目前主流的数据传输还是JSON,但是老的一辈的系统还是避免不了使用XML。XML的解析工具很多,性能各不一样,这里就不一样作介绍了。
初步的解析工具选择-XStream
其实最开始选择的工具是XStream,一开始也没啥问题,功能也实现了,主要是网上很多介绍的也是这个,性能相对比较好,所以就选择了。但是到了性能压测的时候,TPS就惨不忍睹了,低的可怜,我直接上Jmeter的测试报报告图,看了初步有个数。下面我再贴上使用fasterxml解析的性能测试报告,对比一下就知道差距了,毕竟没有对比就没有伤害。XStream的用法可以自行百度了解,这里也不作讲解以及贴代码了。
fasterxml的使用
下面直接贴代码以及简单简单的介绍。
请求XML
<Message>
<Message_Header>
<msgId></msgId>
<msgRef>66666</msgRef>
<channel>admin</channel>
<fromNodeId>admin</fromNodeId>
<toServiceCode>YW-20200811-0UORY</toServiceCode>
<externalReferenceNo>444</externalReferenceNo>
<transactionBranch>88888</transactionBranch>
<transactionDate>20120918</transactionDate>
<msgPri>1</msgPri>
<msgVer>1.0.1</msgVer>
<replyCode></replyCode>
<replyText></replyText>
</Message_Header>
<Message_Body>
<request>
<trcd>aaaaaa</trcd>
<channo>57</channo>
<charset>UTF-8</charset>
<bussid></bussid>
<branchno>444</branchno>
<signbranchno>555</signbranchno>
<immedflag>0</immedflag>
<lastsndtime></lastsndtime>
<msgcode></msgcode>
<msgdesc></msgdesc>
<jyrq>8月28日</jyrq>
<jysj>10:38</jysj>
<name>张三</name>
<mobile>18007729591</mobile>
<cdno1></cdno1>
<cdno2>555555</cdno2>
<amount>1.00</amount>
<endbal>8888</endbal>
<curtype>¥</curtype>
<mark1></mark1>
<mark2></mark2>
<mark3></mark3>
<mark4>666</mark4>
</request>
</Message_Body>
</Message>
pom.xml
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<version>2.10.0</version>
</dependency>
报文的实体类定义
EsbMessageReq.java
@JacksonXmlRootElement(localName = "Message")
@JsonIgnoreProperties(ignoreUnknown = true)
public class EsbMessageReq {
@JsonProperty("Message_Body")
private EsbMessageBodyReq esbMessageBodyRequest;
@JsonProperty("Message_Header")
private EsbMessageHead esbMessageHead;
public EsbMessageBodyReq getEsbMessageBodyRequest() {
return esbMessageBodyRequest;
}
public void setEsbMessageBodyRequest(EsbMessageBodyReq esbMessageBodyRequest) {
this.esbMessageBodyRequest = esbMessageBodyRequest;
}
public EsbMessageHead getEsbMessageHead() {
return esbMessageHead;
}
public void setEsbMessageHead(EsbMessageHead esbMessageHead) {
this.esbMessageHead = esbMessageHead;
}
EsbMessageHead.java
@JacksonXmlRootElement(localName = "Message_Header")
@JsonIgnoreProperties(ignoreUnknown = true)
public class EsbMessageHead {
@JsonProperty("msgId")
private String msgId;
@JsonProperty("msgRef")
private String msgRef;
@JsonProperty("channel")
private String channel;
@JsonProperty("fromNodeId")
private String fromNodeId;
@JsonProperty("toServiceCode")
private String toServiceCode;
@JsonProperty("externalReferenceNo")
private String externalReferenceNo;
@JsonProperty("transactionBranch")
private String transactionBranch;
@JsonProperty("transactionDate")
private String transactionDate;
@JsonProperty("msgPri")
private String msgPri;
@JsonProperty("msgVer")
private String msgVer;
@JsonProperty("replyCode")
private String replyCode;
@JsonProperty("replyText")
private String replyText;
public String getMsgId() {
return msgId;
}
public void setMsgId(String msgId) {
this.msgId = msgId;
}
public String getMsgRef() {
return msgRef;
}
public void setMsgRef(String msgRef) {
this.msgRef = msgRef;
}
public String getChannel() {
return channel;
}
public void setChannel(String channel) {
this.channel = channel;
}
public String getFromNodeId() {
return fromNodeId;
}
public void setFromNodeId(String fromNodeId) {
this.fromNodeId = fromNodeId;
}
public String getToServiceCode() {
return toServiceCode;
}
public void setToServiceCode(String toServiceCode) {
this.toServiceCode = toServiceCode;
}
public String getExternalReferenceNo() {
return externalReferenceNo;
}
public void setExternalReferenceNo(String externalReferenceNo) {
this.externalReferenceNo = externalReferenceNo;
}
public String getTransactionBranch() {
return transactionBranch;
}
public void setTransactionBranch(String transactionBranch) {
this.transactionBranch = transactionBranch;
}
public String getTransactionDate() {
return transactionDate;
}
public void setTransactionDate(String transactionDate) {
this.transactionDate = transactionDate;
}
public String getMsgPri() {
return msgPri;
}
public void setMsgPri(String msgPri) {
this.msgPri = msgPri;
}
public String getMsgVer() {
return msgVer;
}
public void setMsgVer(String msgVer) {
this.msgVer = msgVer;
}
public String getReplyCode() {
return replyCode;
}
public void setReplyCode(String replyCode) {
this.replyCode = replyCode;
}
public String getReplyText() {
return replyText;
}
public void setReplyText(String replyText) {
this.replyText = replyText;
}
EsbMessageBodyReq.java
@JacksonXmlRootElement(localName = "Message_Body")
@JsonIgnoreProperties(ignoreUnknown = true)
public class EsbMessageBodyReq {
@JsonProperty("request")
private BodyReq request;
public BodyReq getRequest() {
return request;
}
public void setRequest(BodyReq request) {
this.request = request;
}
}
BodyReq.java
@JacksonXmlRootElement(localName = "request")
@JsonIgnoreProperties(ignoreUnknown = true)
public class BodyReq { @JsonProperty("trcd")
private String trcd;
@JsonProperty("channo")
private String channo;
@JsonProperty("charset")
private String charset;
@JsonProperty("bussid")
private String bussid;
@JsonProperty("branchno")
private String branchno;
@JsonProperty("signbranchno")
private String signbranchno;
@JsonProperty("immedflag")
private String immedflag;
@JsonProperty("lastsndtime")
private String lastsndtime;
@JsonProperty("msgcode")
private String msgcode;
@JsonProperty("msgdesc")
private String msgdesc;
@JsonProperty("jyrq")
private String jyrq;
@JsonProperty("jysj")
private String jysj;
@JsonProperty("name")
private String name;
@JsonProperty("mobile")
private String mobile;
@JsonProperty("cdno1")
private String cdno1;
@JsonProperty("cdno2")
private String cdno2;
@JsonProperty("amount")
private String amount;
@JsonProperty("endbal")
private String endbal;
@JsonProperty("tdbal")
private String tdbal;
@JsonProperty("curtype")
private String curtype;
@JsonProperty("mark1")
private String mark1;
@JsonProperty("mark2")
private String mark2;
@JsonProperty("mark3")
private String mark3;
@JsonProperty("mark4")
private String mark4;
@JsonProperty("tjd")
private String tjd;
@JsonProperty("useWord")
private String useWord;
@JsonProperty("RESULT")
private EsbResult result;
@JsonProperty("msgcontent")
private String msgcontent;
@JsonProperty("trntype")
private String trntype;
@JsonProperty("orderNo")
private String orderNo;
@JsonProperty("validTime")
private String validTime;
@JsonProperty("filename")
private String filename;
public String getTrcd() {
return trcd;
}
public void setTrcd(String trcd) {
this.trcd = trcd;
}
public String getChanno() {
return channo;
}
public void setChanno(String channo) {
this.channo = channo;
}
public String getCharset() {
return charset;
}
public void setCharset(String charset) {
this.charset = charset;
}
public String getBussid() {
return bussid;
}
public void setBussid(String bussid) {
this.bussid = bussid;
}
public String getBranchno() {
return branchno;
}
public void setBranchno(String branchno) {
this.branchno = branchno;
}
public String getSignbranchno() {
return signbranchno;
}
public void setSignbranchno(String signbranchno) {
this.signbranchno = signbranchno;
}
public String getImmedflag() {
return immedflag;
}
public void setImmedflag(String immedflag) {
this.immedflag = immedflag;
}
public String getLastsndtime() {
return lastsndtime;
}
public void setLastsndtime(String lastsndtime) {
this.lastsndtime = lastsndtime;
}
public String getMsgcode() {
return msgcode;
}
public void setMsgcode(String msgcode) {
this.msgcode = msgcode;
}
public String getMsgdesc() {
return msgdesc;
}
public void setMsgdesc(String msgdesc) {
this.msgdesc = msgdesc;
}
public String getJyrq() {
return jyrq;
}
public void setJyrq(String jyrq) {
this.jyrq = jyrq;
}
public String getJysj() {
return jysj;
}
public void setJysj(String jysj) {
this.jysj = jysj;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getCdno1() {
return cdno1;
}
public void setCdno1(String cdno1) {
this.cdno1 = cdno1;
}
public String getCdno2() {
return cdno2;
}
public void setCdno2(String cdno2) {
this.cdno2 = cdno2;
}
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
public String getEndbal() {
return endbal;
}
public void setEndbal(String endbal) {
this.endbal = endbal;
}
public String getCurtype() {
return curtype;
}
public void setCurtype(String curtype) {
this.curtype = curtype;
}
public String getMark1() {
return mark1;
}
public void setMark1(String mark1) {
this.mark1 = mark1;
}
public String getMark2() {
return mark2;
}
public void setMark2(String mark2) {
this.mark2 = mark2;
}
public String getMark3() {
return mark3;
}
public void setMark3(String mark3) {
this.mark3 = mark3;
}
public String getMark4() {
return mark4;
}
public void setMark4(String mark4) {
this.mark4 = mark4;
}
public String getFilename() {
return filename;
}
public void setFilename(String filename) {
this.filename = filename;
}
public String getTdbal() {
return tdbal;
}
public void setTdbal(String tdbal) {
this.tdbal = tdbal;
}
public String getTjd() {
return tjd;
}
public void setTjd(String tjd) {
this.tjd = tjd;
}
public String getUseWord() {
return useWord;
}
public void setUseWord(String useWord) {
this.useWord = useWord;
}
public EsbResult getResult() {
return result;
}
public void setResult(EsbResult result) {
this.result = result;
}
public String getMsgcontent() {
return msgcontent;
}
public void setMsgcontent(String msgcontent) {
this.msgcontent = msgcontent;
}
public String getTrntype() {
return trntype;
}
public void setTrntype(String trntype) {
this.trntype = trntype;
}
public String getOrderNo() {
return orderNo;
}
public void setOrderNo(String orderNo) {
this.orderNo = orderNo;
}
public String getValidTime() {
return validTime;
}
public void setValidTime(String validTime) {
this.validTime = validTime;
}
组装以及解析工具
XmlUtil.java
public class XmlUtils {
private static final ObjectMapper OBJECT_MAPPER = new XmlMapper();
/**
* 将Object 转 XML 字符串
*/
public static String objectToXmlString(Object object) throws JsonProcessingException {
// 美化输出的 xml 字符串
OBJECT_MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
// 字段为null,自动忽略,不再序列化
OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return OBJECT_MAPPER.writeValueAsString(object);
}
/**
* XMl > 将XML字符串转换为JavaBean对象, ObjectMapper还提供了很多重载方法,详情查看源码,这里不一一列举
*/
public static <T> T xmlStringToObject(String xmlStr, Class<T> tClass) throws IOException {
// 字段为null,自动忽略,不再序列化
OBJECT_MAPPER.setSerializationInclusion(JsonInclude.Include.NON_NULL);
return OBJECT_MAPPER.readValue(xmlStr, tClass);
}
}
Test.java
public class Test {
public static void main(String[] args) {
String xml = "<Message>\n" +
" <Message_Header>\n" +
" <msgId></msgId>\n" +
" <msgRef>66666</msgRef>\n" +
" <channel>admin</channel>\n" +
" <fromNodeId>admin</fromNodeId>\n" +
" <toServiceCode>YW-20200811-0UORY</toServiceCode>\n" +
" <externalReferenceNo>444</externalReferenceNo>\n" +
" <transactionBranch>88888</transactionBranch>\n" +
" <transactionDate>20120918</transactionDate>\n" +
" <msgPri>1</msgPri>\n" +
" <msgVer>1.0.1</msgVer>\n" +
" <replyCode></replyCode>\n" +
" <replyText></replyText>\n" +
" </Message_Header>\n" +
" <Message_Body>\n" +
" <request>\n" +
" <trcd>aaaaaa</trcd>\n" +
" <channo>57</channo>\n" +
" <charset>UTF-8</charset>\n" +
" <bussid></bussid>\n" +
" <branchno>444</branchno>\n" +
" <signbranchno>555</signbranchno>\n" +
" <immedflag>0</immedflag>\n" +
" <lastsndtime></lastsndtime>\n" +
" <msgcode></msgcode>\n" +
" <msgdesc></msgdesc>\n" +
" <jyrq>8月28日</jyrq>\n" +
" <jysj>10:38</jysj>\n" +
" <name>张三</name>\n" +
" <mobile>18007729591</mobile>\n" +
" <cdno1></cdno1>\n" +
" <cdno2>555555</cdno2>\n" +
" <amount>1.00</amount>\n" +
" <endbal>8888</endbal>\n" +
" <curtype>¥</curtype>\n" +
" <mark1></mark1>\n" +
" <mark2></mark2>\n" +
" <mark3></mark3>\n" +
" <mark4>666</mark4>\n" +
" </request>\n" +
" </Message_Body>\n" +
"</Message>";
try {
EsbMessageReq esbMessageReq = XmlUtils.xmlStringToObject(xml, EsbMessageReq.class);
System.out.println(esbMessageReq);
} catch (IOException e) {
e.printStackTrace();
}
}
}
输出结果:
EsbMessageReq{esbMessageBodyRequest=EsbMessageBody{request=BodyReq{trcd=‘aaaaaa’, channo=‘57’, charset=‘UTF-8’, bussid=’’, branchno=‘444’, signbranchno=‘555’, immedflag=‘0’, lastsndtime=’’, msgcode=’’, msgdesc=’’, jyrq=‘8月28日’, jysj=‘10:38’, name=‘张三’, mobile=‘18007729591’, cdno1=’’, cdno2=‘555555’, amount=‘1.00’, endbal=‘8888’, tdbal=‘null’, curtype=‘¥’, mark1=’’, mark2=’’, mark3=’’, mark4=‘666’, tjd=‘null’, useWord=‘null’, result=null, msgcontent=‘null’, trntype=‘null’, orderNo=‘null’, validTime=‘null’, filename=‘null’}}, esbMessageHead=EsbMessageHead{msgId=’’, msgRef=‘66666’, channel=‘admin’, fromNodeId=‘admin’, toServiceCode=‘YW-20200811-0UORY’, externalReferenceNo=‘444’, transactionBranch=‘88888’, transactionDate=‘20120918’, msgPri=‘1’, msgVer=‘1.0.1’, replyCode=’’, replyText=’’}}
在这里顺便贴上优化后的性能压测:
后记
所以XML解析第三方的库选择对性能有很大影响,在这里极力推荐fasterxml,测试性能TPS大概比XStream快了近40倍左右,有兴趣的可以自行测试,感谢阅读。