Jackson 2.x 系列【25】Spring Boot 集成之起步依赖、自动配置

有道无术,术尚可求,有术无道,止于术。

本系列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-jdk8jackson-datatype-jsr310jackson-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的主要作用是将JacksonPropertiesModule中的配置,集成到应用环境中。

注册了一个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);
        };
    }
相关推荐
paopaokaka_luck1 分钟前
[371]基于springboot的高校实习管理系统
java·spring boot·后端
捂月1 小时前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
FIN技术铺3 小时前
Spring Boot框架Starter组件整理
java·spring boot·后端
小码的头发丝、4 小时前
Spring Boot 注解
java·spring boot
午觉千万别睡过4 小时前
RuoYI分页不准确问题解决
spring boot
2301_811274314 小时前
大数据基于Spring Boot的化妆品推荐系统的设计与实现
大数据·spring boot·后端
编程重生之路5 小时前
Springboot启动异常 错误: 找不到或无法加载主类 xxx.Application异常
java·spring boot·后端
politeboy5 小时前
k8s启动springboot容器的时候,显示找不到application.yml文件
java·spring boot·kubernetes
世间万物皆对象12 小时前
Spring Boot核心概念:日志管理
java·spring boot·单元测试
qq_174482857513 小时前
springboot基于微信小程序的旧衣回收系统的设计与实现
spring boot·后端·微信小程序