公司的项目用到了rocketMQ,看到里面有段这样的代码,生产者生产消息

1
2
3
4
5
6
7
private static final ObjectMapper OM = new ObjectMapper();
...
Message message = new Message(this.topic, "create", uid.toString(), OM.writeValueAsBytes(uid));
message.setWaitStoreMsgOK(true);
SendResult sendResult = producer.send(message, new SelectMessageQueueByHash(), uid);
...

消费者的代码是这样的:

1
2
3
4
...
String body = new String(msg.getBody(), Charset.defaultCharset());
uid = Integer.parseInt(body);
...

初看起来没有毛病,而且线上也正常运行,于是我也照葫芦画瓢,写了一个类似的,生产者代码:

1
2
3
4
5
...
Message msg = new Message(topic, tag, payNo, OM.writeValueAsBytes(payNo));
msg.setWaitStoreMsgOK(true);
SendResult sendResult = producer.send(msg, new SelectMessageQueueByHash(), payNo);
...

消费者代码如下:

1
2
3
4
...
String payNo = new String(msg.getBody(), Charset.defaultCharset());
bizSalePayService.callbackPaySystem(payNo);
...

结果在调试的时候发现,这个payNo已经不是生产者塞进去的那个值了,很是纳闷,于是写了一段代码测试一下

1
2
3
4
5
6
7
8
9
10
11
...
String payNo = "{\"uid\":123456}";
ObjectMapper om = new ObjectMapper();
byte[] payNoBytes = om.writeValueAsBytes(payNo);
String payNo1 = new String(payNoBytes, Charset.defaultCharset());
if (payNo.equals(payNo1)) {
System.out.println("yes");
} else {
System.out.println("no");
}
...

发现这样输出是no,断点调试发现payNo1的值是”\”{\”uid\”:123456}\””,也就是说,多了一对引号,那么这对引号哪里来的?打个断点看一下jackson的源码实现:

image

image
可以看到jackson在转byte的时候在字符串的首尾增加了引号。
到这里大概就知道原因了,可以理解为jackson有一套自己的“协议”,为不同的类型增加了一些字符,所以我们在转回去的时候也需要使用它提供的接口,而不能强行将byte转为String:

1
String payNo2 = om.readValue(payNoBytes, String.class);

这样payNo2和payNo就一模一样了。
总结成一句话就是对不熟悉的类库使用时要慎重。