Fuente: juejin.cn/post/7156439842958606349
-
Revisión de incidentes en línea
-
Restauración de escenarios
-
Análisis de código fuente
-
Principio de serialización de JavaBeanSerizlier
-
Diagrama de flujo de serialización
-
-
Código de muestra
-
especificación de código
-
Tres casos de serialización de alta frecuencia
Revisión de incidentes en línea
Hace algún tiempo, un colega agregó una función muy simple. Cuando se lanzó el código por la noche, review
pensó en los valores emprendedores y trabajadores de la empresa. Agregó temporalmente una línea de registros de registro. Pensó que básicamente no había ningún problema con solo una línea de registro simple. Llame a la policía, revierta el código rápidamente, encuentre el problema y elimine el código para agregar registros, y vuelva a conectarse.
Un blog separado de front-end y back-end basado en Spring Boot + MyBatis Plus + Vue 3.2 + Vite + Element Plus, que incluye un sistema de gestión en segundo plano que admite funciones como artículos, categorías, gestión de etiquetas y paneles.
Dirección de GitHub: https://github.com/weiwosuoai/WeBlog
Dirección de la casa rural: https://gitee.com/AllenJiang/WeBlog
Restauración de escenarios
❝
define un
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("中国");
}
}
❝
Definir la clase de prueba
FastJonTest
❞
public class FastJonTest {
@Test
public void testSerialize() {
CountryDTO countryDTO = new CountryDTO();
String str = JSON.toJSONString(countryDTO);
System.out.println(str);
}
}
Error al ejecutar 空指针
:
puntero nulo
Del mensaje de error se puede ver que el método fue ejecutado durante el proceso de serialización isChinaName()
, en este momento this.country
la variable está vacía, por lo que surge el problema:
-
¿ Por qué se realiza la serialización
isChinaName()
? -
Por extensión, ¿qué métodos se ejecutarán durante el proceso de serialización?
Análisis de código fuente
Observe la información de la pila del enlace de la llamada a través de la depuración
imagen
imagen
En la cadena de llamadas, una clase ASMSerializer_1_CountryDTO.write
se genera dinámicamente FastJson
usando tecnología .asm
ASMSerializer_1_CountryDTO
❝
Uno de los escenarios de uso de la tecnología asm es generar dinámicamente clases para reemplazar
java
la reflexión, a fin de evitar la sobrecarga de reflexión durante la ejecución repetida.❞
Principio de serialización de JavaBeanSerizlier
En la siguiente figura se puede ver que en el proceso de serialización, el método JavaBeanSerializer
de la clase se llama principalmente write()
.
Clase de implementación de ObjectSerializer JavaBeanSerializer
Se JavaBeanSerializer
obtiene principalmente a través de getObjectWriter()
métodos, mediante getObjectWriter()
la depuración del proceso de ejecución, para encontrar los com.alibaba.fastjson.serializer.SerializeConfig#createJavaBeanSerializer
métodos más críticos y luego para encontrar 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")){
//省略部分代码...
}
}
}
A partir del código, se puede dividir aproximadamente en tres situaciones:
-
@JSONField(.serialize = false, name = "xxx")
anotación -
getXxx()
: El método que comienza con get -
isXxx()
: método que comienza con is
Diagrama de flujo de serialización
Diagrama de flujo de serialización
Un blog separado de front-end y back-end basado en Spring Boot + MyBatis Plus + Vue 3.2 + Vite + Element Plus, que incluye un sistema de gestión en segundo plano que admite funciones como artículos, categorías, gestión de etiquetas y paneles.
Dirección de GitHub: https://github.com/weiwosuoai/WeBlog
Dirección de la casa rural: https://gitee.com/AllenJiang/WeBlog
Código de muestra
/**
* 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";
}
}
El resultado de la operación es:
isChinaName()执行!!
getEnglishName()执行!!
{"chinaName":true,"englishName":"lucy"}
especificación de código
Se puede ver que todavía hay muchas reglas de serialización. Por ejemplo, a veces debe prestar atención al valor de retorno, a veces debe prestar atención a la cantidad de parámetros, a veces debe prestar atención a las anotaciones y, a veces @JSONType
, debe prestar atención @JSONField
a las anotaciones; el grado de dominio de los puntos de conocimiento es diferente, y esta variación puede conducir fácilmente a problemas de código, así que trate de tener una solución recomendada.
Se recomienda usar @JSONField(serialize = false)
para marcar explícitamente los métodos que no participan en la serialización. El siguiente es @JSONField
el código después de usar anotaciones. ¿Puede ver de un vistazo qué métodos no necesitan participar en la serialización?
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";
}
}
Tres casos de serialización de alta frecuencia
Tres casos de serialización de alta frecuencia
Básicamente se sigue el proceso anterior, encontrando problemas --> análisis de principios --> resolución de problemas --> sublimación (especificación de programación).
-
Centrándose en los negocios: resolución de problemas -> cómo elegir una buena solución -> cómo expandir n aplicaciones del sistema con una buena solución;
-
Concéntrese en la tecnología: resuelva un solo problema y domine los principios de esta línea a lo largo de un solo problema.
Pero, de hecho, no estoy satisfecho con este código, porque depende demasiado de FastJson. El efecto que quiero es no depender de ningún marco de serialización JSON en particular. Cuando necesito reemplazarlo, puedo reemplazarlo en cualquier momento.
Y al escribir código, no confíe demasiado en los registros. Solo necesita registrar información importante y crítica, no todos los registros. He visto un sistema de gestión que se ejecuta con discos de 128G en una hora. Casi no hay concurrencia, pero casi todas las solicitudes generan varios registros M. Hablaré de esto por separado más adelante.
Con respecto a las anotaciones de características como @JSONField
y @JSONType
, estandarizaré y daré una nueva solución de desacoplamiento dentro del equipo más adelante y las eliminaré.