有道无术,术尚可求,有术无道,止于术。
本系列Jackson 版本 2.17.0
本系列Spring Boot 版本 3.2.4
源码地址:https://gitee.com/pearl-organization/study-jaskson-demo
文章目录
-
- [1. 前言](#1. 前言)
- [2. 起步依赖](#2. 起步依赖)
- [3. 自动配置](#3. 自动配置)
-
- [3.1 JacksonProperties](#3.1 JacksonProperties)
- [3.2 JacksonAutoConfiguration](#3.2 JacksonAutoConfiguration)
-
- [3.2.1 JacksonMixinConfiguration](#3.2.1 JacksonMixinConfiguration)
- [3.2.2 JacksonObjectMapperBuilderConfiguration](#3.2.2 JacksonObjectMapperBuilderConfiguration)
- [3.2.3 JacksonObjectMapperConfiguration](#3.2.3 JacksonObjectMapperConfiguration)
- [3.2.4 ParameterNamesModuleConfiguration](#3.2.4 ParameterNamesModuleConfiguration)
- [3.2.5 Jackson2ObjectMapperBuilderCustomizerConfiguration](#3.2.5 Jackson2ObjectMapperBuilderCustomizerConfiguration)
- [4. Jackson2ObjectMapperBuilderCustomizer](#4. Jackson2ObjectMapperBuilderCustomizer)
1. 前言
Spring Boot
是当前最流行的Java
应用开发框架,简化开发的同时也导致了很多开发人员只会写业务代码,并不太清楚内部组件和配置细节,一旦出问题或者需要性能优化时,就会显得无从下手。
所以推荐大家要多学习一下基础的应用框架,了解它们的详细用法和核心原理,不要太依赖于Spring Boot
的自动化。
接下来我们学习Spring Boot
是如何集成的Jackson
,并针对开发中常见的问题进行实战演示。
2. 起步依赖
Spring Boot
起步依赖(Starter Dependency
)机制,针对常见场景需要的依赖进行了统一打包处理,使用时只需要引入Starter
包即可。
例如针对JSON
应用场景,在Spring Boot
中提供了spring-boot-starter-json
启动器,默认引入的JSON
库是Jackson
:
java
dependencies {
api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter"))
api("org.springframework:spring-web")
api("com.fasterxml.jackson.core:jackson-databind")
api("com.fasterxml.jackson.datatype:jackson-datatype-jdk8")
api("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")
api("com.fasterxml.jackson.module:jackson-module-parameter-names")
}
除了jackson-databind
,还引入非核心模块jackson-datatype-jdk8
、jackson-datatype-jsr310
、jackson-module-parameter-names
,所以在Spring Boot
环境中,可以直接处理LocalDateTime
。
3. 自动配置
Spring Boot
基于约定大于配置思想,引入了Starter
包后,启动时扫描自动配置类,并自动装配声明的Bean
组件,开发者无需手动进行繁琐的配置,从而提高了开发效率,降低了维护成本。
spring-boot-autoconfigure
模块中包含了对Jackson
的自动配置:
3.1 JacksonProperties
Spring Boot
提供了配置属性类JacksonProperties
,方便我们直接在application.yml
配置文件中指定一些转换策略:
全部属性配置如下:
yml
spring:
jackson:
constructor-detector: EXPLICIT_ONLY
# 设置日志格式化格式,配置为日期格式字符串或完全限定的日期格式类名。例如 yyyy-MM-dd HH:mm:ss
date-format: yyyy-MM-dd HH:mm:ss
# 宽松的全局默认设置
default-leniency: true
# 控制序列化期间包含的属性。使用 Jackson 的 JsonInclude.Include 枚举中的值之一进行配置。
default-property-inclusion: always
# 序列化配置 ,MAP 集合 , Map<SerializationFeature, Boolean>
serialization:
EAGER_SERIALIZER_FETCH: true
# 反序列化特征,Map<DeserializationFeature, Boolean>
deserialization:
USE_BIG_DECIMAL_FOR_FLOATS: true
# ObjectMapper/JsonMapper特征,Map<MapperFeature, Boolean>
mapper:
AUTO_DETECT_GETTERS: true
# 生成器JsonGenerator.Feature,Map<com.fasterxml.jackson.core.JsonGenerator.Feature, Boolean>
generator:
AUTO_CLOSE_TARGET: true
# 地区
locale: zh_CN
# 解析器 Map<Feature, Boolean>
# parser:
# 设置属性命名策略,对应jackson下PropertyNamingStrategy中的常量值,SNAKE_CASE-返回的json驼峰式转下划线,json body下划线传到后端自动转驼峰式
property-naming-strategy: SNAKE_CASE
# 全局时区
time-zone: GMT+8
# 可见性阈值,可用于限制自动检测哪些方法(和字段)。
visibility:
GETTER: ANY
3.2 JacksonAutoConfiguration
Spring Boot
提供了自动配置类JacksonAutoConfiguration
,包含了多个内部配置类:
在自动配置类的static
块中,配置了两个默认特征,设置序列化日志时间不使用时间戳 ,并注册JsonComponentModule Bean
对象,用于注册所有@JsonComponent
标识的Bean
:
java
@AutoConfiguration
@ConditionalOnClass({ObjectMapper.class})
public class JacksonAutoConfiguration {
@Bean
public JsonComponentModule jsonComponentModule() {
return new JsonComponentModule();
}
private static final Map<?, Boolean> FEATURE_DEFAULTS;
static {
Map<Object, Boolean> featureDefaults = new HashMap();
featureDefaults.put(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
featureDefaults.put(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
FEATURE_DEFAULTS = Collections.unmodifiableMap(featureDefaults);
}
// 省略内部配置类
3.2.1 JacksonMixinConfiguration
内部自动配置类JacksonMixinConfiguration
用于扫描@JsonMixin
标识的类并注册,以支持混合注解:
java
@Configuration(proxyBeanMethods = false)
static class JacksonMixinConfiguration {
@Bean
static JsonMixinModuleEntries jsonMixinModuleEntries(ApplicationContext context) {
List<String> packages = AutoConfigurationPackages.has(context) ? AutoConfigurationPackages.get(context)
: Collections.emptyList();
return JsonMixinModuleEntries.scan(context, packages);
}
@Bean
JsonMixinModule jsonMixinModule(ApplicationContext context, JsonMixinModuleEntries entries) {
JsonMixinModule jsonMixinModule = new JsonMixinModule();
jsonMixinModule.registerEntries(entries, context.getClassLoader());
return jsonMixinModule;
}
}
3.2.2 JacksonObjectMapperBuilderConfiguration
内部自动配置类JacksonObjectMapperBuilderConfiguration
注册了一个多例的Jackson2ObjectMapperBuilder
(用于构建ObjectMapper
对象),并调用所有的定制器Jackson2ObjectMapperBuilderCustomizer
进行定制化处理:
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
static class JacksonObjectMapperBuilderConfiguration {
@Bean
@Scope("prototype")
@ConditionalOnMissingBean
Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(ApplicationContext applicationContext,
List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
builder.applicationContext(applicationContext);
customize(builder, customizers);
return builder;
}
private void customize(Jackson2ObjectMapperBuilder builder,
List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
for (Jackson2ObjectMapperBuilderCustomizer customizer : customizers) {
customizer.customize(builder);
}
}
}
3.2.3 JacksonObjectMapperConfiguration
内部自动配置类JacksonObjectMapperConfiguration
注册了一个单例的ObjectMapper Bean
对象到容器中,是使用容器中的Jackson2ObjectMapperBuilder
构建的,并且是线程安全的,所以在使用时直接使用@Autowired
注入该实例即可。
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Jackson2ObjectMapperBuilder.class)
static class JacksonObjectMapperConfiguration {
@Bean
@Primary // 主要的
@ConditionalOnMissingBean // 在应用程序没有注册ObjectMapper时生效
ObjectMapper jacksonObjectMapper(Jackson2ObjectMapperBuilder builder) {
return builder.createXmlMapper(false).build();
}
}
3.2.4 ParameterNamesModuleConfiguration
内部自动配置类ParameterNamesModuleConfiguration
用于注册了ParameterNamesModule
:
java
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ParameterNamesModule.class)
static class ParameterNamesModuleConfiguration {
@Bean
@ConditionalOnMissingBean
ParameterNamesModule parameterNamesModule() {
return new ParameterNamesModule(JsonCreator.Mode.DEFAULT);
}
}
3.2.5 Jackson2ObjectMapperBuilderCustomizerConfiguration
内部自动配置类Jackson2ObjectMapperBuilderCustomizerConfiguration
的主要作用是将JacksonProperties
、Module
中的配置,集成到应用环境中。
注册了一个StandardJackson2ObjectMapperBuilderCustomizer
:
StandardJackson2ObjectMapperBuilderCustomizer
实现了Jackson2ObjectMapperBuilderCustomizer
,所以在自动注册Jackson2ObjectMapperBuilder
时,会调用customize
方法,将JacksonProperties
的配置项都集成到Jackson2ObjectMapperBuilder
中:
4. Jackson2ObjectMapperBuilderCustomizer
Jackson2ObjectMapperBuilderCustomizer
定制器接口,用于对Jackson2ObjectMapperBuilder
的构建行为进行定制:
java
@FunctionalInterface
public interface Jackson2ObjectMapperBuilderCustomizer {
void customize(Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder);
}
他们之间的关系如下所示:
在实际开发中,可以注册Jackson2ObjectMapperBuilderCustomizer
来配置ObjectMapper
:
java
@Bean
public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
return builder -> {
builder.serializerByType(Long.class, com.fasterxml.jackson.databind.ser.std.ToStringSerializer.instance);
builder.deserializerByType(Long.class,com.fasterxml.jackson.databind.ser.std.ToStringSerializer.instance);
};
}