当前位置: 首页 > 后端技术 > Java

我在代码中加了一行log,导致了P1级的线上事故,.大家注意!

时间:2023-04-01 13:23:00 Java

作者:老鹰汤链接:https://juejin.cn/post/715643...在线事故回顾前段时间加了个很简单的功能。晚上上线前review代码的时候,想到了公司勤奋进取的价值观。加上一行log日志,我觉得简单的一行日志基本没有问题。结果刚上线就报了一堆告警。赶紧回滚代码,发现问题,把添加日志的代码删掉,重新上线。场景还原定义一个CountryDTOpublicclassCountryDTO{privateStringcountry;publicvoidsetCountry(Stringcountry){this.country=country;}publicStringgetCountry(){返回这个国家;}publicBooleanisChinaName(){returnthis.country.equals("China");}}定义测试类FastJonTestpublicclassFastJonTest{@TestpublicvoidtestSerialize(){CountryDTOcountryDTO=newCountryDTO();字符串str=JSON.toJSONString(countryDTO);System.out.println(海峡);}}运行时出现空指针错误:从报错信息可以看出,在序列化过程中执行了isChinaName()方法。这时this.country变量为空,那么问题来了:为什么序列化执行isChinaName()毛呢?推而广之,序列化过程中会执行哪些方法呢?源码分析通过debug观察调用链路的栈信息。调用链中的ASMSerializer_1_CountryDTO.write是FastJson利用asm技术动态生成的类ASMSerializer_1_CountryDTO,asm技术的使用场景之一就是用动态生成的类来代替java反射,避免重复执行时的反射开销。JavaBeanSerizlier序列化原理从下图可以看出,在序列化的过程中,主要调用了JavaBeanSerializer类的write()方法。JavaBeanSerializer主要通过getObjectWriter()方法获取。通过调试getObjectWriter()执行过程,找到比较关键的com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer方法,然后com.alibaba.fastjson.util.TypeUtils#computeGetterspublicstaticListcomputeGetters(Classclazz,//JSONTypejsonType,//MapaliasMap,//MapfieldCacheMap,//布尔排序,//PropertyNamingStrategypropertyNamingStrategy//){//省略一些代码。...方法[]方法=clazz.getMethods();for(Methodmethod:methods){//省略一些代码...if(method.getReturnType().equals(Void.TYPE)){continue;}如果(方法。getParameterrTypes().length!=0){继续;}//省略部分代码...JSONFieldannotation=TypeUtils.getAnnotation(method,JSONField.class);//省略一些代码...if(annotation!=null){if(!annotation.serialize()){continue;}if(annotation.name().length()!=0){//省略部分代码...}}if(methodName.startsWith("get")){//省略部分代码...}if(methodName.startsWith("is")){//省略部分代码...}}}从代码中大致可以看出三种情况:@JSONField(.serialize=false,name="xxx")注解getXxx():get开头的方法isXxx():isXxx()开头的方法示例代码/***case1:@JSONField(serialize=false)*case2:getXxx()返回值为void*case3:isXxx()返回值不等于布尔类型*case4:@JSONType(ignores="xxx")*/@JSONType(ignores="otherName")publicclassCountryDTO{privateStr国别;publicvoidsetCountry(Stringcountry){this.country=country;}publicStringgetCountry(){返回这个国家;}publicstaticvoidqueryCountryList(){System.out.println("queryCountryList()执行!!");}publicBooleanisChinaName(){System.out.println("isChinaName()执行!!");返回真;}publicStringgetEnglishName(){System.out.println("getEnglishName()执行!!");返回“露西”;}publicStringgetOtherName(){System.out.println("getOtherName()执行!!");返回“露西”;}/***case1:@JSONField(serialize=false)*/@JSONField(serialize=false)publicStringgetEnglishName2(){System.out.println("getEnglishName2()执行!!");返回“露西”;}/***case2:getXxx()返回值为void*/publicvoidgetEnglishName3(){System.out.println("getEnglishName3()被执行!!");}/***case3:isXxx()返回值不等于布尔类型*/publicStringisChinaName2(){System.out.println("isChinaName2()执行!!");返回“是中国名2”;}}运行结果为:执行了isChinaName()!!getEnglishName()!!{"chinaName":true,"englishName":"lucy"}从代码规范可以看出顺序还是有的自定义的规则很多,比如有时候需要注意返回值,有时候需要注意参数个数,有时候需要注意@JSONType注解,有时候需要注意@JSONField注解;当一个事物有多种区分方式时,由于团队成员对知识点的掌握程度不同。这种差异很容易导致代码问题,因此请尝试使用推荐的解决方案。这里推荐使用@JSONField(serialize=false)显式标记方法,不参与序列化。以下是推荐的解决方案。代码,能不能一眼看出哪些方法不需要参与序列化。公共类CountryDTO{私有字符串国家;publicvoidsetCountry(Stringcountry){this.country=country;}publicStringgetCountry(){返回这个国家;}@JSONField(serialize=false)publicstaticvoidqueryCountryList(){System.out.println("queryCountryList()执行!!");}publicBooleanisChinaName(){System.out.println("isChinaName()执行!!");返回真;}publicStringgetEnglishName(){System.out.println("getEnglishName()执行!!");返回“露西”;}@JSONField(serialize=false)publicStringgetOtherName(){System.out.println("getOtherName()执行!!");返回“露西”;}@JSONField(serialize=false)publicStringgetEnglishName2(){System.out.println("getEnglishName2()执行!!");返回“露西”;}@JSONField(序列化=假)publicvoidgetEnglishName3(){System.out.println("getEnglishName3()执行!!");}@JSONField(serialize=false)publicStringisChinaName2(){System.out.println("isChinaName2()执行!!");返回“是中国名2”;}}高频连载的三个案例上面的流程基本上是发现问题-->原理分析-->解决问题-->升华(编程规范)围绕业务:解决问题-->如何选择好的解决方案->如何用好的方案扩展n个系统应用;aroundtechnology:解决单个问题,掌握沿着单个问题这条线的原理。近期热点文章推荐:1.1000+Java面试题及答案(2022最新版)2.厉害了!Java协程来了。..3.SpringBoot2.x教程,太全面了!4.不要用爆破爆满画面,试试装饰者模式,这才是优雅的方式!!5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!