Jackson 自动配置
概述
Jackson 是 Spring Boot 默认的 JSON 序列化/反序列化框架。JacksonAutoConfiguration 负责自动配置 ObjectMapper,并通过 HttpMessageConvertersAutoConfiguration 将其注册到 Spring MVC 的 MappingJackson2HttpMessageConverter 中。
本文将深入拆解 Jackson 自动配置的完整链路,涵盖配置加载、Module 自动注册、@JsonComponent 扫描、消息转换器注册等 10 个细节点。
本文基于 Spring Boot 3.x + Jackson 2.x 源码分析。
1. JacksonAutoConfiguration 的 @ConditionalOnClass
1.1 源码
java
// JacksonAutoConfiguration.java
@AutoConfiguration
@ConditionalOnClass(ObjectMapper.class) // jackson-databind
@ConditionalOnBean(Jackson2ObjectMapperBuilder.class)
public class JacksonAutoConfiguration {
// 配置 1: 创建 ObjectMapper
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(ObjectMapper.class)
static class JacksonObjectMapperConfiguration {
@Bean
@Primary
@ConditionalOnMissingBean
ObjectMapper jacksonObjectMapper(
Jackson2ObjectMapperBuilder builder) {
// 使用 Jackson2ObjectMapperBuilder 创建 ObjectMapper
return builder.createXmlMapper(false).build();
}
}
// 配置 2: ObjectMapperBuilder 定制化
@Configuration(proxyBeanMethods = false)
static class JacksonObjectMapperBuilderConfiguration {
@Bean
@Scope("prototype") // 每次调用创建新实例
@ConditionalOnMissingBean
Jackson2ObjectMapperBuilder jacksonObjectMapperBuilder(
ApplicationContext applicationContext,
List<Jackson2ObjectMapperBuilderCustomizer> customizers) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
// 应用所有 Jackson2ObjectMapperBuilderCustomizer
builder.applicationContext(applicationContext);
customize(builder, customizers);
return builder;
}
}
}1.2 @ConditionalOnClass(ObjectMapper.class) 的条件评估
java
// ObjectMapper.class 位于 jackson-databind 包
// 依赖坐标:
// <dependency>
// <groupId>com.fasterxml.jackson.core</groupId>
// <artifactId>jackson-databind</artifactId>
// </dependency>
//
// Spring Boot Starter Web 已经包含了该依赖
// spring-boot-starter-web → jackson-databind
// 如果 classpath 中没有 jackson-databind
// → JacksonAutoConfiguration 不生效
// → 使用其他 MessageConverter(如 GsonHttpMessageConverter、JsonbHttpMessageConverter)1.3 Jackson 相关自动配置的依赖关系
java
// JacksonAutoConfiguration 与其他自动配置的关系:
//
// JacksonAutoConfiguration
// └─ @ConditionalOnClass(ObjectMapper.class)
// └─ @ConditionalOnBean(Jackson2ObjectMapperBuilder.class)
// ↓ 创建 ObjectMapper
//
// HttpMessageConvertersAutoConfiguration
// └─ @ConditionalOnBean(ObjectMapper.class)
// ↓ 创建 MappingJackson2HttpMessageConverter
//
// WebMvcAutoConfiguration
// └─ 接收到 HttpMessageConverters
// ↓ 将 MappingJackson2HttpMessageConverter 加入 Spring MVC2. JacksonProperties 的 15 个配置项字段
2.1 源码
java
// JacksonProperties.java
@ConfigurationProperties(prefix = "spring.jackson")
public class JacksonProperties {
// 1. 日期格式
private String dateFormat; // spring.jackson.date-format
// 2. 时区
private TimeZone timeZone; // spring.jackson.time-zone (如 "Asia/Shanghai")
// 3. 地区
private Locale locale; // spring.jackson.locale (如 "zh_CN")
// 4. 属性命名策略
private PropertyNamingStrategy propertyNamingStrategy;
// spring.jackson.property-naming-strategy
// 可选: LOWER_CAMEL_CASE, SNAKE_CASE, UPPER_CAMEL_CASE, LOWER_CASE, KEBAB_CASE
// 对应: camelCase, snake_case, UpperCamelCase, lower_case, kebab-case
// 5. SerializationFeature 开关
private Map<SerializationFeature, Boolean> serialization;
// spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
// spring.jackson.serialization.INDENT_OUTPUT=true
// 6. DeserializationFeature 开关
private Map<DeserializationFeature, Boolean> deserialization;
// spring.jackson.deserialization.FAIL_ON_UNKNOWN_PROPERTIES=false
// 7. MapperFeature 开关
private Map<MapperFeature, Boolean> mapper;
// spring.jackson.mapper.DEFAULT_VIEW_INCLUSION=true
// 8. JsonParser.Feature 开关
private Map<JsonParser.Feature, Boolean> parser;
// spring.jackson.parser.ALLOW_SINGLE_QUOTES=true
// 9. JsonGenerator.Feature 开关
private Map<JsonGenerator.Feature, Boolean> generator;
// spring.jackson.generator.ESCAPE_NON_ASCII=true
// 10. Visibility 可见性
private Map<Visibility.Std, JsonAutoDetect.Visibility> visibility;
// spring.jackson.visibility.GETTER=ANY
// spring.jackson.visibility.FIELD=ANY
// spring.jackson.visibility.IS_GETTER=NONE
// spring.jackson.visibility.SETTER=NONE
// spring.jackson.visibility.CREATOR=NONE
// 11. 默认属性包含
private JsonInclude.Include defaultPropertyInclusion;
// spring.jackson.default-property-inclusion=non_null
// 12. 默认属性包含(setter 相关)
private JsonInclude.Include defaultPropertyInclusionForSetter;
// 13. 默认属性包含(getter 相关)
private JsonInclude.Include defaultPropertyInclusionForGetter;
// 14. 写入时的宽松处理
private boolean writeDatesAsTimestamps = true; // 兼容旧版本
// 15. 空值/空字符串处理
private Map<String, Boolean> deserializationByType;
}2.2 完整配置示例
yaml
spring:
jackson:
# 基础配置
date-format: yyyy-MM-dd HH:mm:ss # 日期格式
time-zone: Asia/Shanghai # 时区
locale: zh_CN # 地区
default-property-inclusion: non_null # 忽略 null 值
# 属性命名策略
property-naming-strategy: LOWER_CAMEL_CASE # 默认
# 序列化特性
serialization:
WRITE_DATES_AS_TIMESTAMPS: false # 日期不输出时间戳
INDENT_OUTPUT: true # 格式化 JSON 输出
FAIL_ON_EMPTY_BEANS: false # 空 Bean 不报错
WRITE_ENUMS_USING_TO_STRING: true # 枚举用 toString()
# 反序列化特性
deserialization:
FAIL_ON_UNKNOWN_PROPERTIES: false # 忽略未知属性
READ_ENUMS_USING_TO_STRING: true # 枚举用 toString() 反序列化
ACCEPT_SINGLE_VALUE_AS_ARRAY: true # 单值作为数组接收
# Mapper 特性
mapper:
DEFAULT_VIEW_INCLUSION: true # 默认视图包含
USE_ANNOTATIONS: true # 使用注解
# 可见性
visibility:
GETTER: ANY # 所有 getter 都序列化
FIELD: ANY # 所有字段都序列化
IS_GETTER: NONE # 忽略 isXxx 方法
SETTER: NONE # 忽略 setter(使用字段)
CREATOR: NONE # 忽略构造器参数3. Jackson2ObjectMapperBuilder.configure() 的 20 个配置项
3.1 源码
java
// Jackson2ObjectMapperBuilder.java
public class Jackson2ObjectMapperBuilder {
private ObjectMapper objectMapper;
// 构建 ObjectMapper
public <T extends ObjectMapper> T build() {
ObjectMapper mapper;
try {
// 1. 创建 ObjectMapper 实例
if (this.createXmlMapper) {
mapper = new XmlMapper();
} else {
mapper = new ObjectMapper();
}
} catch (ClassNotFoundException ex) {
mapper = new ObjectMapper();
}
// 2. 执行 configure() —— 核心配置方法
configure(mapper);
return (T) mapper;
}
public void configure(ObjectMapper objectMapper) {
// 这个 ObjectMapper 用于后续读取已经配置的状态
this.objectMapper = objectMapper;
// 1. 日期格式
if (this.dateFormat != null) {
objectMapper.setDateFormat(this.dateFormat);
}
// 2. 时区
if (this.locale != null) {
objectMapper.setLocale(this.locale);
}
// 3. 地区
if (this.timeZone != null) {
objectMapper.setTimeZone(this.timeZone);
}
// 4. 注解支持(默认启用 AnnotationIntrospector)
// 支持 @JsonProperty, @JsonIgnore, @JsonFormat 等
// 5. 可见性配置
if (this.visibility != null) {
objectMapper.setVisibility(this.visibility);
}
// 6. 属性命名策略
if (this.propertyNamingStrategy != null) {
objectMapper.setPropertyNamingStrategy(
this.propertyNamingStrategy);
}
// 7. SerializationFeature —— 10+ 个
if (this.features != null) {
for (Map.Entry<?, ?> entry : this.features.entrySet()) {
// 实际会分类注册 SerializationFeature、DeserializationFeature、MapperFeature
configureFeature(objectMapper, (Class<?>) entry.getKey(),
entry.getValue());
}
}
// 8. 默认属性包含
if (this.serializationInclusion != null) {
objectMapper.setSerializationInclusion(
this.serializationInclusion);
}
// 9. MixIn 注解(外部提供注解映射)
if (this.mixIns != null) {
this.mixIns.forEach(objectMapper::addMixIn);
}
// 10. 序列化器注册
if (this.serializers != null) {
// 注册自定义 JsonSerializer
SimpleModule module = new SimpleModule();
module.setSerializers(new SimpleSerializers(this.serializers));
objectMapper.registerModule(module);
}
// 11. 反序列化器注册
if (this.deserializers != null) {
SimpleModule module = new SimpleModule();
module.setDeserializers(new SimpleDeserializers(this.deserializers));
objectMapper.registerModule(module);
}
// 12. Module 自动注册
if (!this.modules.isEmpty()) {
// 调用 registerModules() 注册所有 Module
// 详见第 4 节
registerModules(objectMapper);
}
// 13. Module 手动注册
if (this.modulesToInstall != null) {
objectMapper.registerModules(this.modulesToInstall);
}
// 14. FilterProvider 过滤器
if (this.filters != null) {
objectMapper.setFilterProvider(this.filters);
}
// 15. 注解扫描器
if (this.annotationIntrospector != null) {
objectMapper.setAnnotationIntrospector(
this.annotationIntrospector);
}
// 16. TypeFactory(类型工厂)
if (this.typeFactory != null) {
objectMapper.setTypeFactory(this.typeFactory);
}
// 17. ClassIntrospector(类内省器)
if (this.classIntrospector != null) {
objectMapper.setClassIntrospector(this.classIntrospector);
}
// 18. HandlerInstantiator(处理器实例化器)
if (this.handlerInstantiator != null) {
objectMapper.setHandlerInstantiator(
this.handlerInstantiator);
}
// 19. PropertyNamingStrategy 额外设置
// 已经设置过,但 builder 模式单独配置时覆盖
// 20. DefaultTyping(默认类型处理)
if (this.defaultTyping != null) {
objectMapper.activateDefaultTyping(this.defaultTyping);
}
// 应用所有的 Jackson2ObjectMapperBuilderCustomizer
// 详见 Customizer 部分
}
}3.2 常用配置的分类
| 类别 | 配置方法 | 常用项 |
|---|---|---|
| 日期/时区 | #setDateFormat() / #setTimeZone() | yyyy-MM-dd HH:mm:ss、Asia/Shanghai |
| 序列化特征 | #configure(SerializationFeature, boolean) | WRITE_DATES_AS_TIMESTAMPS、INDENT_OUTPUT |
| 反序列化特征 | #configure(DeserializationFeature, boolean) | FAIL_ON_UNKNOWN_PROPERTIES、ACCEPT_SINGLE_VALUE_AS_ARRAY |
| Mapper 特征 | #configure(MapperFeature, boolean) | DEFAULT_VIEW_INCLUSION、USE_ANNOTATIONS |
| 命名策略 | #setPropertyNamingStrategy() | SNAKE_CASE、KEBAB_CASE |
| Module 注册 | #registerModule() | JavaTimeModule、Jdk8Module |
4. registerModules() 自动注册所有 Module
4.1 源码
java
// Jackson2ObjectMapperBuilder.java
private void registerModules(ObjectMapper objectMapper) {
// 1. 先注册已添加的 Module
if (!this.modules.isEmpty()) {
for (Module module : this.modules) {
objectMapper.registerModule(module);
}
}
// 2. 从 classpath 自动发现所有 Module
if (this.moduleClassLoader != null) {
// 使用 ObjectMapper.findModules() 自动搜索
List<Module> modules = ObjectMapper.findModules(this.moduleClassLoader);
for (Module module : modules) {
objectMapper.registerModule(module);
}
}
}
// 在 Spring Boot 中的调用链
// Jackson2ObjectMapperBuilder 的 build() 方法
// → configure(objectMapper)
// → registerModules(objectMapper)
// → ObjectMapper.findModules(classLoader)
// → ServiceLoader.load(Module.class, classLoader)
// → META-INF/services/com.fasterxml.jackson.databind.Module4.2 ObjectMapper.findModules() 的实现
java
// ObjectMapper.java (Jackson)
public static List<Module> findModules(ClassLoader classLoader) {
// 1. 使用 ServiceLoader 加载所有 Module 实现
Iterator<Module> moduleIterator = SecurityUtil
.safeGetServiceLoader(Module.class, classLoader)
.iterator();
// 2. 收集到列表
ArrayList<Module> modules = new ArrayList<>();
while (moduleIterator.hasNext()) {
Module module = moduleIterator.next();
modules.add(module);
}
return modules;
}4.3 Classpath 中自动发现的常见 Module
| Module | 触发条件 | 作用 |
|---|---|---|
Jdk8Module | jackson-datatype-jdk8 | Optional<T>、OptionalInt 等序列化 |
JavaTimeModule | jackson-datatype-jsr310 | LocalDate、LocalDateTime、Instant 等 JSR310 类型 |
GeoModule | jackson-datatype-jts (JTS) | Point、Polygon 等几何类型 |
KotlinModule | jackson-module-kotlin | Kotlin 数据类序列化(无参构造器) |
Hibernate5Module | jackson-datatype-hibernate5 | Hibernate 懒加载代理处理 |
GuavaModule | jackson-datatype-guava | Optional<T>、ImmutableList 等 Guava 类型 |
AfterburnerModule | jackson-module-afterburner | 通过字节码生成加速序列化 |
BlackbirdModule | jackson-module-blackbird | Afterburner 的替代方案(Java 9+) |
5. @JsonComponent 注解被 JsonComponentBean 扫描
5.1 @JsonComponent 注解
java
// @JsonComponent.java
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component // 本身是 @Component,可被组件扫描发现
public @interface JsonComponent {
/**
* 指定此组件作用于的 JSON 元素类型
* 默认自动检测
*/
@AliasFor(annotation = Component.class, attribute = "value")
String value() default "";
}5.2 JsonComponentModule 的注册
java
// JacksonAutoConfiguration.java
@Configuration(proxyBeanMethods = false)
static class JacksonObjectMapperBuilderConfiguration {
@Bean
@ConditionalOnMissingBean
JsonComponentModule jsonComponentModule() {
// 创建 JsonComponentModule
// 它会扫描所有 @JsonComponent 标注的类
return new JsonComponentModule();
}
}
// @JsonComponentModule 被作为 Module 注册到 ObjectMapper
// Jackson2ObjectMapperBuilder 自动发现 Module
// → 扫描 @JsonComponent → 注册自定义序列化器/反序列化器5.3 JsonComponentModule 扫描逻辑
java
// JsonComponentModule.java
public class JsonComponentModule extends SimpleModule {
public JsonComponentModule(ApplicationContext applicationContext) {
// 1. 从 ApplicationContext 获取所有 @JsonComponent Bean
Map<String, Object> beans = applicationContext
.getBeansWithAnnotation(JsonComponent.class);
// 2. 遍历并注册
for (Object bean : beans.values()) {
registerJsonComponent(bean);
}
}
private void registerJsonComponent(Object bean) {
// 检测 Bean 的接口类型,判断是 Serializer 还是 Deserializer
JsonComponentType type = JsonComponentType.fromBean(bean);
switch (type) {
case SERIALIZER:
registerSerializer((JsonSerializer<?>) bean);
break;
case DESERIALIZER:
registerDeserializer((JsonDeserializer<?>) bean);
break;
case KEY_SERIALIZER:
registerKeySerializer((JsonSerializer<?>) bean);
break;
case KEY_DESERIALIZER:
registerKeyDeserializer((KeyDeserializer) bean);
break;
}
}
}
// JsonComponentType 分类
enum JsonComponentType {
SERIALIZER, // 实现 JsonSerializer
DESERIALIZER, // 实现 JsonDeserializer
KEY_SERIALIZER, // 实现 JsonSerializer + @JsonComponent(type = KEY)
KEY_DESERIALIZER; // 实现 KeyDeserializer
}5.4 使用示例
java
// 1. 自定义序列化器
@JsonComponent
public class UserSerializer extends JsonSerializer<User> {
@Override
public void serialize(User user, JsonGenerator gen,
SerializerProvider serializers) throws IOException {
gen.writeStartObject();
gen.writeStringField("uid", user.getId().toString());
gen.writeStringField("name", user.getUsername());
gen.writeEndObject();
}
}
// 2. 自定义反序列化器
@JsonComponent
public class UserDeserializer extends JsonDeserializer<User> {
@Override
public User deserialize(JsonParser p, DeserializationContext ctx)
throws IOException {
JsonNode node = p.getCodec().readTree(p);
User user = new User();
user.setId(Long.parseLong(node.get("uid").asText()));
user.setUsername(node.get("name").asText());
return user;
}
}
// 3. 单个类中同时包含序列化器和反序列化器
@JsonComponent
public class UserComponent {
public static class Serializer extends JsonSerializer<User> {
// ...
}
public static class Deserializer extends JsonDeserializer<User> {
// ...
}
}6. Jdk8Module 注册 Optionals 序列化
6.1 Module 注册
java
// Jdk8Module 在 classpath 自动发现(META-INF/services/com.fasterxml.jackson.databind.Module)
// 依赖:
// <dependency>
// <groupId>com.fasterxml.jackson.datatype</groupId>
// <artifactId>jackson-datatype-jdk8</artifactId>
// </dependency>
public class Jdk8Module extends SimpleModule {
public Jdk8Module() {
super(PackageVersion.VERSION);
// 注册序列化器
addSerializer(new OptionalSerializer());
addSerializer(new OptionalIntSerializer());
addSerializer(new OptionalLongSerializer());
addSerializer(new OptionalDoubleSerializer());
// 注册反序列化器
addDeserializer(Optional.class, new OptionalDeserializer());
addDeserializer(OptionalInt.class, new OptionalIntDeserializer());
addDeserializer(OptionalLong.class, new OptionalLongDeserializer());
addDeserializer(OptionalDouble.class, new OptionalDoubleDeserializer());
}
}6.2 序列化效果
java
// 序列化
public class Person {
private String name;
private Optional<String> email; // 序列化为 "email" : "xxx@example.com"
private Optional<String> phone; // 序列化为 "phone" : null(如果为空)
}
// 默认:Optional 字段作为普通字段序列化
// Person(name="John", email=Optional.of("john@example.com"), phone=Optional.empty())
// → {"name":"John","email":"john@example.com","phone":null}
// 配合 Spring Boot 配置:忽略 null
// spring.jackson.default-property-inclusion=non_null
// → {"name":"John","email":"john@example.com"}7. JavaTimeModule 注册 JSR310
7.1 Module 注册
java
// JavaTimeModule 在 classpath 自动发现
// 依赖:
// <dependency>
// <groupId>com.fasterxml.jackson.datatype</groupId>
// <artifactId>jackson-datatype-jsr310</artifactId>
// </dependency>
public class JavaTimeModule extends SimpleModule {
public JavaTimeModule() {
super(PackageVersion.VERSION);
// LocalDate
addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
// LocalTime
addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_LOCAL_TIME));
addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
// LocalDateTime
addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ISO_LOCAL_DATE_TIME));
// Instant
addSerializer(Instant.class, new InstantSerializer(InstantSerializer.INSTANCE, false));
addDeserializer(Instant.class, new InstantDeserializer());
// ZonedDateTime
addSerializer(ZonedDateTime.class, ZonedDateTimeSerializer.INSTANCE);
addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);
// Duration
addSerializer(Duration.class, DurationSerializer.INSTANCE);
addDeserializer(Duration.class, DurationDeserializer.INSTANCE);
// Period
addSerializer(Period.class, PeriodSerializer.INSTANCE);
addDeserializer(Period.class, PeriodDeserializer.INSTANCE);
// ... 更多 JSR310 类型
}
}7.2 序列化效果
java
// 默认(WRITE_DATES_AS_TIMESTAMPS=true)
LocalDateTime.now() → [2026, 7, 25, 14, 30, 0] // 时间戳数组
// 配置后(WRITE_DATES_AS_TIMESTAMPS=false + date-format)
// spring.jackson.date-format=yyyy-MM-dd HH:mm:ss
// spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false
LocalDateTime.now() → "2026-07-25 14:30:00" // 格式化字符串7.3 完整配置示例
yaml
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
serialization:
WRITE_DATES_AS_TIMESTAMPS: falsejava
public class Order {
private LocalDateTime createTime; // → "2026-07-25 14:30:00"
private LocalDate orderDate; // → "2026-07-25"
private Instant processedAt; // → "2026-07-25T06:30:00Z"
private Duration processingTime; // → "PT30M"
private Period warrantyPeriod; // → "P1Y"
}8. GeoModule 注册 Geometry 类型
8.1 Module 注册
java
// GeoModule 在 classpath 自动发现(可选)
// 依赖:
// <dependency>
// <groupId>com.fasterxml.jackson.datatype</groupId>
// <artifactId>jackson-datatype-jts</artifactId>
// </dependency>
public class GeoModule extends SimpleModule {
public GeoModule() {
super("GeoModule", new Version(1, 0, 0, null, "com.fasterxml.jackson.datatype", "jackson-datatype-jts"));
// 注册 Geometry 类型的序列化器/反序列化器
// 使用 JTS 的 WKT(Well-Known Text)格式
addSerializer(Geometry.class, new GeometrySerializer());
addDeserializer(Geometry.class, new GeometryDeserializer());
// 具体类型
addSerializer(Point.class, new GeometrySerializer());
addDeserializer(Point.class, new GeometryDeserializer());
addSerializer(Polygon.class, new GeometrySerializer());
addDeserializer(Polygon.class, new GeometryDeserializer());
addSerializer(LineString.class, new GeometrySerializer());
addDeserializer(LineString.class, new GeometryDeserializer());
}
}8.2 序列化效果
java
// GeoJSON 格式
public class Store {
private String name;
private Point location; // 经纬度坐标
private Polygon area; // 营业区域
}
// Point(121.4737, 31.2304) → { "type": "Point", "coordinates": [121.4737, 31.2304] }
// Polygon(...) → { "type": "Polygon", "coordinates": [[[x1,y1],[x2,y2],...]] }9. HttpMessageConvertersAutoConfiguration 注册 MappingJackson2HttpMessageConverter
9.1 源码
java
// HttpMessageConvertersAutoConfiguration.java
@AutoConfiguration
@ConditionalOnClass(HttpMessageConverter.class)
public class HttpMessageConvertersAutoConfiguration {
// 配置 MappingJackson2HttpMessageConverter
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(ObjectMapper.class)
@ConditionalOnBean(ObjectMapper.class)
static class MappingJackson2HttpMessageConverterConfiguration {
@Bean
@ConditionalOnMissingBean
@ConditionalOnProperty(
prefix = "spring.http.converters",
name = "preferred-json-mapper",
havingValue = "jackson",
matchIfMissing = true)
MappingJackson2HttpMessageConverter
mappingJackson2HttpMessageConverter(
ObjectMapper objectMapper) {
// 使用 JacksonAutoConfiguration 创建的 ObjectMapper
// 包装为 MappingJackson2HttpMessageConverter
return new MappingJackson2HttpMessageConverter(objectMapper);
}
}
// 配置 HttpMessageConverters(收集所有 MessageConverter)
@Bean
@ConditionalOnMissingBean
HttpMessageConverters messageConverters(
ObjectProvider<HttpMessageConverter<?>> converters) {
// 收集所有 HttpMessageConverter Bean
// 包括 MappingJackson2HttpMessageConverter
return new HttpMessageConverters(
converters.orderedStream().collect(Collectors.toList()));
}
}9.2 条件评估
java
// MappingJackson2HttpMessageConverter 的生效条件:
//
// 1. @ConditionalOnClass(ObjectMapper.class)
// ✓ jackson-databind 在 classpath 中
//
// 2. @ConditionalOnBean(ObjectMapper.class)
// ✓ JacksonAutoConfiguration 成功创建了 ObjectMapper
//
// 3. @ConditionalOnProperty(prefix = "spring.http.converters",
// name = "preferred-json-mapper", havingValue = "jackson", matchIfMissing = true)
// ✓ 默认使用 Jackson
// 可选(除非显式指定其他 JSON 框架):
// - spring.http.converters.preferred-json-mapper=gson → 使用 Gson
// - spring.http.converters.preferred-json-mapper=jsonb → 使用 Jsonb9.3 在 Spring MVC 中的注册
java
// WebMvcAutoConfigurationAdapter.java 中
// HttpMessageConverters -> configureMessageConverters()
@Override
public void configureMessageConverters(
List<HttpMessageConverter<?>> converters) {
// 收集所有已注册的 HttpMessageConverter
// 包括 MappingJackson2HttpMessageConverter
converters.addAll(this.messageConverters.getConverters());
}9.4 完整的 Jackson 自动配置全链路
JacksonAutoConfiguration
│
├─ JacksonObjectMapperBuilderConfiguration
│ └─ @Bean Jackson2ObjectMapperBuilder
│ └─ 注册所有 Jackson2ObjectMapperBuilderCustomizer
│
├─ JacksonObjectMapperConfiguration
│ └─ @Bean ObjectMapper
│ ├─ Jackson2ObjectMapperBuilder.build()
│ ├─ configure(): 20 个配置项
│ ├─ registerModules(): 自动发现 Module
│ └─ @JsonComponent 注册自定义序列化器
│
└─ JacksonMixinConfiguration(可选)
└─ MixIn 注入
HttpMessageConvertersAutoConfiguration
│
└─ MappingJackson2HttpMessageConverterConfiguration
└─ @ConditionalOnBean(ObjectMapper.class)
└─ @Bean MappingJackson2HttpMessageConverter
└─ new MappingJackson2HttpMessageConverter(objectMapper)
WebMvcAutoConfiguration
│
└─ WebMvcAutoConfigurationAdapter
└─ configureMessageConverters()
└─ 添加 MappingJackson2HttpMessageConverter10. 日期格式 spring.jackson.date-format 的两种模式
10.1 两种模式
yaml
# 模式 1: SimpleDateFormat 字符串
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
# 这种方式下,Jackson 内部会创建 SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
# 适用于 java.util.Date
#
# 注意: SimpleDateFormat 不是线程安全的!
# Jackson 通过 ThreadLocal 来解决线程安全问题
# 模式 2: DateFormat 实例(通过 @Bean 注册)
@Bean
public Jackson2ObjectMapperBuilderCustomizer dateFormatCustomizer() {
return builder -> {
// 使用线程安全的 DateFormat
builder.dateFormat(new ISO8601DateFormat());
// 或者使用 SimpleDateFormat(Jackson 内部会做线程安全包装)
builder.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
};
}10.2 源码
java
// Jackson2ObjectMapperBuilder.java
private DateFormat dateFormat;
public Jackson2ObjectMapperBuilder dateFormat(DateFormat dateFormat) {
this.dateFormat = dateFormat;
return this;
}
// 在 configure() 中的处理
@Override
public void configure(ObjectMapper objectMapper) {
// ...
if (this.dateFormat != null) {
// 包装为线程安全的 DateFormat
objectMapper.setDateFormat(this.dateFormat);
}
// ...
}
// ObjectMapper 中的处理
public ObjectMapper setDateFormat(DateFormat dateFormat) {
// 如果传入的是 SimpleDateFormat(非线程安全)
// ObjectMapper 会将其包装为线程安全的版本
this._serializationConfig = (SerializationConfig)
this._serializationConfig.with(new StdDateFormat());
this._deserializationConfig = (DeserializationConfig)
this._deserializationConfig.with(dateFormat);
return this;
}10.3 日期配置的效果对比
yaml
# 配置
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: Asia/Shanghai
serialization:
WRITE_DATES_AS_TIMESTAMPS: false| Java 类型 | 输出值 |
|---|---|
Date | "2026-07-25 14:30:00" |
LocalDateTime | "2026-07-25 14:30:00" |
LocalDate | "2026-07-25" |
Instant | "2026-07-25 06:30:00"(UTC) |
ZonedDateTime | "2026-07-25T14:30:00+08:00" |
10.4 使用 @JsonFormat 覆盖全局配置
java
public class Order {
// 覆盖全局 spring.jackson.date-format 配置
@JsonFormat(pattern = "yyyy/MM/dd", timezone = "Asia/Shanghai")
private Date createDate;
// 使用 ISO 格式
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone = "UTC")
private Instant processedAt;
}总结
| # | 细节点 | 核心要点 |
|---|---|---|
| ① | @ConditionalOnClass(ObjectMapper.class) | 需要 jackson-databind 在 classpath,Starter Web 默认包含 |
| ② | JacksonProperties 15 个配置项 | dateFormat、timeZone、serialization、deserialization、mapper、parser、generator、visibility 等 |
| ③ | Jackson2ObjectMapperBuilder.configure() 20 个配置项 | 日期/时区/序列化特征/反序列化特征/Mapper 特征/命名策略/Module 注册/可见性等 |
| ④ | registerModules() 自动注册 | ObjectMapper.findModules() → ServiceLoader 从 classpath 发现所有 Module |
| ⑤ | @JsonComponent 扫描 | JsonComponentModule 检测 Bean 类型:SERIALIZER/DESERIALIZER/KEY_SERIALIZER/KEY_DESERIALIZER |
| ⑥ | Jdk8Module | Optional<T>、OptionalInt、OptionalLong、OptionalDouble 序列化 |
| ⑦ | JavaTimeModule | LocalDate、LocalDateTime、Instant、ZonedDateTime、Duration、Period 等 JSR310 类型 |
| ⑧ | GeoModule | Point、Polygon、LineString 序列化为 GeoJSON 格式 |
| ⑨ | MappingJackson2HttpMessageConverter | @ConditionalOnBean(ObjectMapper.class) 条件,由 HttpMessageConverters 收集并注册到 Spring MVC |
| ⑩ | 日期格式两种模式 | SimpleDateFormat 字符串(在 yml 中配置)vs DateFormat 实例(通过 Jackson2ObjectMapperBuilderCustomizer 注册) |