A line of log logs caused a P1-level online accident!

Author: Eagle Soup
Link: https://juejin.cn/post/7156439842958606349

Online Incident Review

Some time ago, I added a very simple function. When I coded before going online at night, reviewI thought of the company’s hard-working and enterprising values ​​and temporarily added a line of log logs. I thought that there was basically no problem with just one line of simple logs. As a result, there were a bunch of alarms after the launch. Hurry up Rolled back the code, found the problem, deleted the code that added the log, and went online again.

Scenario restoration

defines aCountryDTO

public class CountryDTO {
    private String country;

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCountry() {
        return this.country;
    }

    public Boolean isChinaName() {
        return this.country.equals("中国");
    }
}

Define the test classFastJonTest

public class FastJonTest {
    @Test
    public void testSerialize() {
        CountryDTO countryDTO = new CountryDTO();
        String str = JSON.toJSONString(countryDTO);
        System.out.println(str);
    }
}

Error when running 空指针:

From the error message, it can be seen that the method was executed during the serialization process isChinaName(). At this time, this.countrythe variable is empty, so the problem arises:

  • Why is serialization performed isChinaName()?
  • By extension, what methods will be executed during the serialization process?

Recommend an open source and free Spring Boot practical project:

https://github.com/javastacks/spring-boot-best-practice

Source code analysis

Observe the stack information of the call link through debug

In the call chain, a class ASMSerializer_1_CountryDTO.writeis dynamically generated FastJsonusing technology ,asmASMSerializer_1_CountryDTO

One of the usage scenarios of asm technology is to dynamically generate classes to replace javareflection, so as to avoid reflection overhead during repeated execution

JavaBeanSerizlier serialization principle

It can be seen from the figure below that in the process of serialization, the method JavaBeanSerializerof the class is mainly called write().

It JavaBeanSerializeris mainly obtained through getObjectWriter()methods, through getObjectWriter()debugging the execution process, to find more critical com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializermethods, and then to findcom.alibaba.fastjson.util.TypeUtils#computeGetters

public static List<FieldInfo> computeGetters(Class<?> clazz, //
                                                 JSONType jsonType, //
                                                 Map<String,String> aliasMap, //
                                                 Map<String,Field> fieldCacheMap, //
                                                 boolean sorted, //
                                                 PropertyNamingStrategy propertyNamingStrategy //
    ){
        //省略部分代码....
        Method[] methods = clazz.getMethods();
        for(Method method : methods){
            //省略部分代码...
            if(method.getReturnType().equals(Void.TYPE)){
                continue;
            }
            if(method.getParameterTypes().length != 0){
                continue;
            }
            //省略部分代码...
            JSONField annotation = 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")){
             //省略部分代码...
            }
        }
}

From the code, it can be roughly divided into three situations:

  • @JSONField(.serialize = false, name = "xxx")annotation
  • getXxx(): The method starting with get
  • isXxx(): method starting with is

Serialization flowchart

Serialization.png

sample code

/**
 * case1: @JSONField(serialize = false)
 * case2: getXxx()返回值为void
 * case3: isXxx()返回值不等于布尔类型
 * case4: @JSONType(ignores = "xxx")
 */
@JSONType(ignores = "otherName")
public class CountryDTO {
    private String country;

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCountry() {
        return this.country;
    }

    public static void queryCountryList() {
        System.out.println("queryCountryList()执行!!");
    }

    public Boolean isChinaName() {
        System.out.println("isChinaName()执行!!");
        return true;
    }

    public String getEnglishName() {
        System.out.println("getEnglishName()执行!!");
        return "lucy";
    }

    public String getOtherName() {
        System.out.println("getOtherName()执行!!");
        return "lucy";
    }

    /**
     * case1: @JSONField(serialize = false)
     */
    @JSONField(serialize = false)
    public String getEnglishName2() {
        System.out.println("getEnglishName2()执行!!");
        return "lucy";
    }

    /**
     * case2: getXxx()返回值为void
     */
    public void getEnglishName3() {
        System.out.println("getEnglishName3()执行!!");
    }

    /**
     * case3: isXxx()返回值不等于布尔类型
     */
    public String isChinaName2() {
        System.out.println("isChinaName2()执行!!");
        return "isChinaName2";
    }
}

The result of the operation is:

isChinaName()执行!!
getEnglishName()执行!!
{"chinaName":true,"englishName":"lucy"}

code specification

It can be seen that there are still many serialization rules. For example, sometimes you need to pay attention to the return value, sometimes you need to pay attention to the number of parameters, sometimes you need to pay attention to @JSONTypeannotations, and sometimes you need to pay attention @JSONFieldto annotations; The degree of mastery of knowledge points is different, and this variance can easily lead to code problems, so try to have a recommended solution. It is recommended to use @JSONField(serialize = false)the explicit annotation method not to participate in serialization. The following is the code after using the recommended solution. Can you see at a glance which methods do not need to participate in serialization.

public class CountryDTO {
    private String country;

    public void setCountry(String country) {
        this.country = country;
    }

    public String getCountry() {
        return this.country;
    }

    @JSONField(serialize = false)
    public static void queryCountryList() {
        System.out.println("queryCountryList()执行!!");
    }

    public Boolean isChinaName() {
        System.out.println("isChinaName()执行!!");
        return true;
    }

    public String getEnglishName() {
        System.out.println("getEnglishName()执行!!");
        return "lucy";
    }

    @JSONField(serialize = false)
    public String getOtherName() {
        System.out.println("getOtherName()执行!!");
        return "lucy";
    }

    @JSONField(serialize = false)
    public String getEnglishName2() {
        System.out.println("getEnglishName2()执行!!");
        return "lucy";
    }

    @JSONField(serialize = false)
    public void getEnglishName3() {
        System.out.println("getEnglishName3()执行!!");
    }

    @JSONField(serialize = false)
    public String isChinaName2() {
        System.out.println("isChinaName2()执行!!");
        return "isChinaName2";
    }
}

Three cases of high frequency serialization

The above process basically follows the discovery of problems --> principle analysis --> problem solving --> sublimation (programming specification).

  • Focusing on business: solving problems -> how to choose a good solution -> how to expand n system applications with a good solution;
  • Focus on technology: solve a single problem, and master the principles of this line along a single problem.

Recent hot article recommendation:

1. 1,000+ Java interview questions and answers (2022 latest version)

2. Brilliant! Java coroutines are coming. . .

3. Spring Boot 2.x tutorial, too comprehensive!

4. Don't fill the screen with explosions and explosions, try the decorator mode, this is the elegant way! !

5. The latest release of "Java Development Manual (Songshan Edition)", download quickly!

Feel good, don't forget to like + forward!

Guess you like

Origin blog.csdn.net/youanyyou/article/details/132299207