背景
其实最近一直想写些帮助大家提高架构底蕴的东西。无奈最近当家的身体抱恙,我白天上班,晚上照顾病人,没有多余的精力 点、线、面的横向思考技术的问题。倒是“无为空自老,含叹负平生”的人生感慨多一些。今天还是谈谈点上的东西。
记得早些时候,被别人要求写算法代码没写出来,后来我刷了百道leetcode。算法题再也没难住我了。但是想来,平时工作中是还是真的少些这些底层代码为妙,业务代码有业务代码的写法。写业务代码最忌讳:“炫技”。和做人一样,讲究“技高不炫技”。下面来介绍一个由于侵入了框架内部引起的故障。
使用Java反射引起的报错
我们平时用Spring框架写Controller进行http请求处理时,框架帮我们做了JavaBean到传输数据的转换。在内部,实际上数据会先转成map再转成我们要处理的JavaBean。这次,在一个RPC泛化调用的场景(泛化调用主要用于没有接口API的情况下。不需要引入接口 jar 包,而是直接通过 通用接口来发起服务调用,参数及返回值中的所有 pojo均用 map 表示)。有个同学客户端处理时,自己写了一个JavaBean转成Map的方式,他是这么写的:
public static Map<String,Object> objectTpMap(Object obj) { Map<String,Object> map = new HashMap(); Class objectClass = obj.getClass(); while(objectClass != null) { Field[] declaredFields = objectClass.getDeclaredFields(); for(Field field : declaredFields) { field.setAccessible(true); resultMap.put(field.getName(), field.get(object)); } } return resultMap; }
这里,在做JavaBean到Map转化时,用了反射的方法,将对象的所有属性(包含private final类型)都提取出来,传给服务端。服务端组件内部,开始时反序列化时,使用的是getField方法查找这个map中的每一个key。如果对象是private final类型是获取不到的,所以没有影响。后来组件升级,反序列化时,并没有使用getField方法,而是使用了getDeclaredField方法,就可以获取到private final类型的属性,进行赋值操作的时候就产生了问题。
这个bug经过了一两年时间才引起了事故。让人意想不到,恢复和排查的响应时间都会收到影响。
后记
能写出这样的代码,究其原因,大致有两种:一种遇到这个问题,经过搜索资料和思考,觉得这样可以实现,就没有做更多的思考;另一种是抱着学习的态度,想用一些之前不常用的技术解决问题。这两种原因写出的代码都是建立在对原理了解不透彻的基础上,相当危险。
最近在看《山河令》,里面有个诗词底蕴极高的温客行。说话时引经据典,天花乱坠。见到周子舒渡船,温客行说:“但度无所苦,我自迎接汝”。这本是大文豪王献之写给他的爱妾桃叶的诗。因为桃叶怕坐船,王献之就说了:“你只管渡江就好,不用想太多,我自然会在江边迎接你。”这里温客行用的隐隐表露出自己的小心思,倒也用的妙。
为了和温客行做对比,里面还出现了个爱附庸风雅的大白兔:曹蔚宁。小曹喜欢阿湘。于是跟阿湘夸她名字好:“九嶷缤兮并迎,灵之来兮如云。”句子里没有出现一个“湘”字。和湘沾边的是前半句“九嶷缤兮并迎“出自屈原的《九歌.湘夫人》。而后半句是曹植的《洛神赋》。洛神叫甄宓啊,和湘字没有半毛钱关系,纯粹是背诗背串了。所以温客行说听小曹背诗,屈原都能被气活过来。这境界反差出来了吧。
但是强如温客行,人家在河边喝水,他本是想打招呼示好的话。他来了一首:“沧浪之水清兮,可以濯我缨;沧浪之水浊兮,可以濯我足。”我只是觉得人家在喝水,你又是洗衣服又是洗脚的,这水喝着真倒胃口。你倒是来一首:“问渠那得清如许?为有源头活水来。” 也能让人觉得水的甘甜。或者来首:“秋水清无底,萧然静客心。” 也可在这炎炎夏日送上一抹凉意。也难怪周子舒不理他。
温客行的漏洞可不止这一处,温客行造了30个假的琉璃甲,带着周子舒去看狗咬狗。他在屋顶上说的是:“冲天香阵透岳阳,满城尽是琉璃甲”。这本是黄巢写菊花的诗:“冲天香阵透长安,满城尽带黄金甲。” 你要是改,也要改的彻底一点,人家菊花是香的,香阵一词用的妙,琉璃甲和香有什么关系吗?冲天香阵肯定是没有,冲天的杀气却是名副其实。说这么多,无非是想说明,还是要敬畏生产。不了解原理还是不要直接在要上生产的代码里尝试。侵入框架底层的代码最好不要写,尽量看看能否用写业务代码的方式来解决。连温客行身上都能找到这么多诗词的错处,平时咱们写的业务代码还怕找不出来Bug?一旦出现生产事故,岂不是丢了排面?