当前位置: 首页 > news >正文

【Spring】Spring哪些源码解决了哪些问题P1

欢迎来到啾啾的博客🐱。
记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。
有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。

目录

  • Spring是怎么处理请求的?
    • Spring请求方法参数与返回怎么处理?
    • Spring如何自定义 JSON 的序列化/反序列化行为
  • Spring是怎么处理事务的?
  • Spring Boot的“约定大于配置”是如何实现的?
  • Spring Boot的自动配置是如何发生的?

Spring是怎么处理请求的?

对处理请求感兴趣的可以看之前的这篇Spring的请求处理

Spring请求方法参数与返回怎么处理?

请求方法中的参数,特别是 @RequestBody 标记的对象是怎么处理的呢?之前的请求篇有提及请求处理,但是没有提及参数,这里补充一下。
在RequestMappingHandlerAdapter调用方法前,它会遍历方法的参数,为每个参数找到合适的HandlerMethodArgumentResolver来解析参数值。
对于标记了@RequestBody的参数,则使用RequestResponseBodyMethodProcessor
RequestResponseBodyMethodProcessor在解析@RequestBody参数时,会从HttpServletRequest中获取输入流,然后遍历注册的HttpMessageConverter列表,找到一个能处理请求Content-Type(如application/json)并且能将输入流转换为目标参数类型的转换器。MappingJackson2HttpMessageConverter就是利用Jackson库将JSON字符串反序列化为Java对象。
![[【Spring】Spring哪些源码解决了哪些问题.png]]

Spring如何自定义 JSON 的序列化/反序列化行为

所以,如果需要自定义 JSON 的序列化/反序列化行为(比如日期格式、null值的处理),我们可以从Jackson2ObjectMapperBuilder / ObjectMapper入手。
Spring Boot 自动配置MappingJackson2HttpMessageConverter时,会使用Jackson2ObjectMapperBuilder来构建底层的ObjectMapper。
可以自定义一个Jackson2ObjectMapperBuilderCustomizer Bean,从而可以对Spring Boot创建的ObjectMapper进行细粒度调整,而不用完全替换它。


import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; // 如果需要排序import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.TimeZone;@Configuration
public class JacksonCustomizerConfig {private static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";private static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";private static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";@Beanpublic Jackson2ObjectMapperBuilderCustomizer customJackson() {return builder -> {// --- 通用配置 ---// 1. 时区配置:序列化和反序列化日期时都使用指定时区//   注意:更推荐在Java对象中使用带时区的类型(如ZonedDateTime),或在DTO转换时处理builder.timeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 或 TimeZone.getDefault()// 2. Null值处理:序列化时,null值的字段不参与序列化builder.serializationInclusion(JsonInclude.Include.NON_NULL);// 其他选项:// JsonInclude.Include.ALWAYS (默认)// JsonInclude.Include.NON_EMPTY (null或空集合、空字符串等不序列化)// JsonInclude.Include.NON_DEFAULT (如果字段值等于其默认值,则不序列化)// 3. 反序列化特性:JSON中有多余的未知字段时,不报错,而是忽略builder.featuresToDisable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);// 如果想开启,则用 featuresToEnable// 4. 序列化特性:对于只有一个元素的数组,序列化时不作为数组,而是作为单个对象(谨慎使用)// builder.featuresToEnable(SerializationFeature.WRITE_SINGLE_ELEM_ARRAYS_UNWRAPPED);// 反之,如果想禁用,则用 featuresToDisable// 5. 序列化特性:日期序列化为时间戳(ms)还是ISO 8601格式字符串//   Spring Boot 默认对于Java 8 Date/Time API是序列化为ISO字符串,//   对于 java.util.Date 是序列化为时间戳。//   禁用时间戳,强制使用ISO格式(或你自定义的格式)builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);// 6. 序列化特性:对于空对象(没有任何字段或getter),序列化时不抛出异常builder.featuresToDisable(SerializationFeature.FAIL_ON_EMPTY_BEANS);// 7. Mapper特性:枚举值使用toString()方法进行序列化/反序列化// builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);// builder.featuresToEnable(DeserializationFeature.READ_ENUMS_USING_TO_STRING);// 8. Mapper特性:反序列化枚举时忽略大小写builder.featuresToEnable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);// --- Java 8 日期时间 API (java.time.*) 格式化 ---// Spring Boot 默认会通过 jackson-datatype-jsr310 模块支持Java 8日期时间类型// 以下是更细致的格式化配置JavaTimeModule javaTimeModule = new JavaTimeModule();// LocalDateTimejavaTimeModule.addSerializer(LocalDateTime.class,new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));javaTimeModule.addDeserializer(LocalDateTime.class,new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)));// LocalDatejavaTimeModule.addSerializer(LocalDate.class,new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));javaTimeModule.addDeserializer(LocalDate.class,new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)));// LocalTimejavaTimeModule.addSerializer(LocalTime.class,new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));javaTimeModule.addDeserializer(LocalTime.class,new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));builder.modulesToInstall(javaTimeModule); // 注册自定义配置的JavaTimeModule// 或者 builder.modules(javaTimeModule); 效果类似,modules会替换现有模块,modulesToInstall会添加// --- 传统日期 (java.util.Date) 格式化 ---// 如果你还在使用 java.util.Date,可以这样配置builder.simpleDateFormat(DEFAULT_DATE_TIME_FORMAT);// --- 其他类型的自定义序列化器/反序列化器 ---// 例如,将Long、BigInteger序列化为字符串,以防止前端JS精度丢失问题builder.serializerByType(Long.class, ToStringSerializer.instance);builder.serializerByType(Long.TYPE, ToStringSerializer.instance); // long基本类型builder.serializerByType(BigInteger.class, ToStringSerializer.instance);// 你还可以添加自定义的序列化器和反序列化器// builder.serializerByType(YourCustomClass.class, new YourCustomSerializer());// builder.deserializerByType(YourCustomClass.class, new YourCustomDeserializer());};}// 如果有多个Customizer,可以使用@Order指定顺序// @Bean// @Order(Ordered.HIGHEST_PRECEDENCE)// public Jackson2ObjectMapperBuilderCustomizer anotherCustomJackson() {//     return builder -> {//         // ...//     };// }
}

Spring是怎么处理事务的?

可以看这篇Spring事务全面解析。

Spring Boot的“约定大于配置”是如何实现的?

Spring Boot 的“约定大于配置”(Convention over Configuration)是一种设计理念,旨在减少开发人员需要做出的决策数量,从而简化开发流程、提高开发效率。

其通过Starters引入一组完成特定功能所需的经过测试和版本兼容的依赖,Starters里面会包含默认bean。

通过自动配置,Spring Boot 会在 classpath 中查找特定的库,并根据找到的库来自动配置你的应用程序。条件化配置@ConditionalOn…在其中发挥了重要作用。
SPI 机制 (通过 spring.factories 或Spring Boot 2.7+ 及 3.x+开始的新的 .imports 文件) 是自动配置用来发现和加载候选配置类的重要手段。Spring Boot 读取这些文件,找到所有潜在的自动配置类,然后通过条件注解(@ConditionalOn…)来决定哪些配置实际生效。

还有就是配置项的合理默认值。Spring Boot 为许多配置项提供了合理的默认值。例如:

  • 内嵌 Tomcat 服务器默认监听 8080 端口。
  • 静态资源默认从 classpath:/static/, classpath:/public/, classpath:/resources/, classpath:/META-INF/resources/ 等路径提供。
  • 日志默认使用 Logback,并配置了控制台输出。

Spring Boot的自动配置是如何发生的?

SpringBoot的启动注解@SpringBootApplication是一个复合注解,其包含@EnableAutoConfiguration。
@EnableAutoConfiguration它通过 @Import(AutoConfigurationImportSelector.class) 导入了一个特殊的 ImportSelector。
![[【Spring】Spring哪些源码解决了哪些问题-2.png]]

AutoConfigurationImportSelector的核心方法是selectImports。selectImports的主要职责是:

  • 收集候选的自动配置类 (Candidate Configurations):
    • 它会去扫描classpath下所有jar包中的 META-INF/spring.factories 文件 (Spring Boot 2.7以前) 或 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 文件 (Spring Boot 2.7+及3.x)。
    • 这些文件列出了所有可用的自动配置类的全限定名,以 org.springframework.boot.autoconfigure.EnableAutoConfiguration 为key。
    • 例如,spring-boot-autoconfigure.jar 中的 spring.factories 文件包含了大量的自动配置类,如 DataSourceAutoConfiguration, WebMvcAutoConfiguration, JacksonAutoConfiguration 等。
http://www.xdnf.cn/news/783343.html

相关文章:

  • WINUI——Magewell视频捕捉开发手记
  • “packageManager“: “pnpm@9.6.0“ 配置如何正确启动项目?
  • Vue-ref 与 props
  • 不止抓请求:5种开发场景中的抓包组合策略(含 Charles 等工具)
  • SpringBoot 数据库导入导出 Xlsx文件的导入与导出 全量导出 数据库导出表格 数据处理 外部数据
  • DHCP 动态主机配置协议(Dynamic host configuration protocol)逐层封装过程: DHCP --> UDP --> IP
  • 从0到1,带你走进Flink的世界
  • iOS 电子书听书功能的实现
  • [yolov11改进系列]基于yolov11使用FasterNet替换backbone用于轻量化网络的python源码+训练源码
  • React---day8
  • Express 集成Sequelize+Sqlite3 默认开启WAL 进程间通信 Conf 打包成可执行 exe 文件
  • mobilnet v4 部署笔记
  • [yolov11改进系列]基于yolov11引入自集成注意力机制SEAM解决遮挡问题的python源码+训练源码
  • 机器学习实战36-基于遗传算法的水泵调度优化项目研究与代码实现
  • 华为云Flexus+DeepSeek征文|基于华为云Flexus X实例的小说转语音助手应用构建实录
  • java int 颜色值转换为string 不带透明度
  • Numpy入门2——视图和副本、伪随机数、切片和索引、数组的轴操作
  • 从0到1认识EFK
  • Oracle 用户/权限/角色管理
  • Linux随记(十八)
  • ElasticSearch+Gin+Gorm简单示例
  • cacti导出的1分钟监控数据csv文件读取并按5分钟求平均值,然后计算95计费值,假设31天的月份
  • graphviz, dot, Error: lost rA sA edge; 独立的模块
  • 项目执行中缺乏灵活应对机制,如何增强适应性?
  • 活动选择问题一文详解
  • 【论文阅读】Dolphin: Document Image Parsing via Heterogeneous Anchor Prompting
  • CppCon 2014 学习:The Perils of Strict Aliasing
  • 业务材料——半导体行业MES系统核心功能工业协议AI赋能
  • 不确定性分析在LEAP能源-环境系统建模中的整合与应用
  • 论文中pdf图片文件太大怎么办