Source: juejin.cn/post/7156439842958606349
-
Online Incident Review
-
Scenario restoration
-
Source code analysis
-
JavaBeanSerizlier serialization principle
-
Serialization flowchart
-
-
sample code
-
code specification
-
Three cases of high frequency serialization
Online Incident Review
Some time ago, a colleague added a very simple function. When the code was launched at night, review
he thought of the company’s hard-working and enterprising values. He temporarily added a line of log logs. He thought that there was basically no problem with just one simple log line. Called the police, quickly rolled back the code, found the problem, deleted the code for adding logs, and went online again.
A front-end and back-end separated blog based on Spring Boot + MyBatis Plus + Vue 3.2 + Vite + Element Plus, including a background management system that supports functions such as articles, categories, tag management, and dashboards.
GitHub address: https://github.com/weiwosuoai/WeBlog
Gitee Address: https://gitee.com/AllenJiang/WeBlog
Scenario restoration
❝
defines a
CountryDTO
❞
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 class
FastJonTest
❞
public class FastJonTest {
@Test
public void testSerialize() {
CountryDTO countryDTO = new CountryDTO();
String str = JSON.toJSONString(countryDTO);
System.out.println(str);
}
}
Error when running 空指针
:
null pointer
From the error message, it can be seen that the method was executed during the serialization process isChinaName()
. At this time, this.country
the variable is empty, so the problem arises:
-
Why is serialization performed
isChinaName()
? -
By extension, what methods will be executed during the serialization process?
Source code analysis
Observe the stack information of the call link through debug
picture
picture
In the call chain, a class ASMSerializer_1_CountryDTO.write
is dynamically generated FastJson
using technology .asm
ASMSerializer_1_CountryDTO
❝
One of the usage scenarios of asm technology is to dynamically generate classes to replace
java
reflection, 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 JavaBeanSerializer
of the class is mainly called write()
.
ObjectSerializer implementation class JavaBeanSerializer
It JavaBeanSerializer
is mainly obtained through getObjectWriter()
methods, through getObjectWriter()
debugging the execution process, to find the more critical com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer
methods, and then to find com.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 flowchart
A front-end and back-end separated blog based on Spring Boot + MyBatis Plus + Vue 3.2 + Vite + Element Plus, including a background management system that supports functions such as articles, categories, tag management, and dashboards.
GitHub address: https://github.com/weiwosuoai/WeBlog
Gitee Address: https://gitee.com/AllenJiang/WeBlog
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 @JSONType
annotations, and sometimes you need to pay attention @JSONField
to 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)
to explicitly mark methods that do not participate in serialization. The following is @JSONField
the code after using annotations. 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
Three cases of high frequency serialization
The above process is basically followed, finding problems --> principle analysis --> solving problems --> 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.
But in fact, I am not satisfied with this code, because it depends too much on FastJson. The effect I want is not to depend on any particular JSON serialization framework. When I need to replace it, I can replace it at any time.
And when writing code, don't rely too much on logs. You only need to log important and critical information, not all logs. I have seen a management system that runs full of 128G disks in one hour. There is almost no concurrency, but almost every request outputs several M logs. I will talk about this separately later.
Regarding feature annotations such as @JSONField
and @JSONType
, I will standardize and give a new decoupling solution within the team later, and remove them.