【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解
Spring Boot 源码学习系列

HttpEncodingAutoConfiguration 详解
- 引言
- 往期内容
- 主要内容
- 1. CharacterEncodingFilter
- 2. HttpEncodingAutoConfiguration
- 2.1 加载自动配置组件
- 2.2 过滤自动配置组件
- 2.2.1 涉及注解
- 2.2.2 characterEncodingFilter 方法
- 2.2.3 localeCharsetMappingsCustomizer 方法
- 总结
引言
前面的博文,我们从源码角度介绍了自动装配流程。虽然带大家从整体上有了清晰的认识,但是我们还不能熟练地运用。本篇就以 Spring Boot 内置的 http 编码功能为例,来带大家分析一下 HttpEncodingAutoConfiguration 的整个自动配置的过程。

往期内容
在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:
| Spring Boot 源码学习 |
| Spring Boot 项目介绍 |
| Spring Boot 核心运行原理介绍 |
| 【Spring Boot 源码学习】@EnableAutoConfiguration 注解 |
| 【Spring Boot 源码学习】@SpringBootApplication 注解 |
| 【Spring Boot 源码学习】走近 AutoConfigurationImportSelector |
| 【Spring Boot 源码学习】自动装配流程源码解析(上) |
| 【Spring Boot 源码学习】自动装配流程源码解析(下) |
| 【Spring Boot 源码学习】深入 FilteringSpringBootCondition |
| 【Spring Boot 源码学习】OnClassCondition 详解 |
| 【Spring Boot 源码学习】OnBeanCondition 详解 |
| 【Spring Boot 源码学习】OnWebApplicationCondition 详解 |
| 【Spring Boot 源码学习】@Conditional 条件注解 |
主要内容
1. CharacterEncodingFilter
在传统的 web 项目中,Spring 为 web 开发提供的一个过滤器【即 org.springframework.web.filter.CharacterEncodingFilter 】,用来防止 web 开发中出现的乱码问题,它是 Spring 通过在 web 请求中定义 request 和 response 的编码来实现。
在 web.xml 中的配置示例如下:
<filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> <init-param> <param-name>forceEncoding</param-name> <param-value>true</param-value> </init-param> </filter>
2. HttpEncodingAutoConfiguration
那么在 Spring Boot 是如何实现的呢?
Spring Boot 是通过内置的 HttpEncodingAutoConfiguration 配置类来完成这一功能。下面我们具体分析一下:
注意: 以下涉及 Spring Boot 源码 均来自版本
2.7.9,其他版本有所出入,可自行查看源码。
2.1 加载自动配置组件
从之前的《【Spring Boot 源码学习】自动装配流程源码解析(上)》中,我们知道 Spring Boot 内部针对自动配置类,会读取如下两个配置文件:
META-INF/spring.factoriesMETA-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

实际上 在 Spring Boot 2.7.9 版本中, Spring Boot 自己内部的 META-INF/spring.factories 中有关自动配置的注册类的配置信息已经被去除掉了,不过其他外围的 jar 中可能有自己的 META-INF/spring.factories 文件,它里面也有关于自动配置注册类的配置信息;
而 Spring Boot 内置的 HttpEncodingAutoConfiguration 配置类,则是配置在上述的第二个配置文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports 中。

2.2 过滤自动配置组件
上述自动配置加载完之后,就来到了 《【Spring Boot 源码学习】自动装配流程源码解析(下)》 介绍的 过滤自动配置组件 逻辑。
这部分数据对应的配置内容在 META-INF/spring-autoconfigure-metadata.properties 文件中:
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration=
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration.ConditionalOnClass=org.springframework.web.filter.CharacterEncodingFilter
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration.ConditionalOnWebApplication=SERVLET
显然这里涉及到了 ConditionalOnClass 和 ConditionalOnWebApplication 注解,我们翻看 HttpEncodingAutoConfiguration 配置类的源码,如下:
@AutoConfiguration
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {private final Encoding properties;public HttpEncodingAutoConfiguration(ServerProperties properties) {this.properties = properties.getServlet().getEncoding();}@Bean@ConditionalOnMissingBeanpublic CharacterEncodingFilter characterEncodingFilter() {// 。。。}@Beanpublic LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {// 。。。}// ...
}
2.2.1 涉及注解
我们先来看看上述 HttpEncodingAutoConfiguration 配置类涉及到的注解,如下:
@AutoConfiguration: 该类是一个自动配置类,Spring Boot 会根据项目中的依赖自动配置这个类的实例。@EnableConfigurationProperties(ServerProperties.class):启用ServerProperties类的配置属性,这样在配置文件中就可以使用server.servlet.encoding属性来配置字符编码。@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET):该配置类只有在基于 servlet 的 web 应用程序中才会被实例化。@ConditionalOnClass(CharacterEncodingFilter.class):只有在项目中存在CharacterEncodingFilter类时才会生效。@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true):只有在配置文件中server.servlet.encoding属性的值为"enabled"时才会生效;当然如果配置文件中没有这个属性,也默认会生效。@Bean:用于声明一个方法创建的对象是一个 Spring 管理的 Bean。Spring 容器会自动管理这个 Bean 的生命周期,包括依赖注入、初始化和销毁等。@ConditionalOnMissingBean:只有在当前 Spring 容器中不存在指定类型的 Bean 时,才会执行被注解的方法。这样可以用于确保在需要的时候才创建某个 Bean,避免重复创建。
其中 ServerProperties 类的属性值对应着 application.yml 或 application.properties 中的配置,通过注解@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) 实现的属性注入。
有关属性注入的内容后续笔者会另外介绍,我们先来看看ServerProperties 类相关的部分源码 和 对应的配置参数:
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {// 。。。private final Servlet servlet = new Servlet();// 。。。public static class Servlet {// 。。。@NestedConfigurationPropertyprivate final Encoding encoding = new Encoding();// 。。。}// 。。。
}public class Encoding {// 默认的HTTP编码,用于Servlet应用程序。public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;// HTTP请求和响应的字符集。如果未显式设置,将添加到"Content-Type"头中private Charset charset = DEFAULT_CHARSET;// 是否强制在HTTP请求和响应上使用配置的字符集的标志private Boolean force;// 是否强制在HTTP请求上使用配置的字符集的标志。当"force"未指定时,默认为true。private Boolean forceRequest;// 是否强制在HTTP响应上使用配置的字符集的标志。private Boolean forceResponse;// 将区域设置映射到字符集以进行响应编码的映射。private Map<Locale, Charset> mapping;// 。。。
}
当然在 application.properties 中,我们就可以添加如下的配置:
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
# server.servlet.encoding.force-request=true
# ...其他配置省略
注意:
server.servlet.encoding.force=true和server.servlet.encoding.force-request=true这两个配置项实际上具有相同的功能,它们都决定是否强制对客户端请求进行字符编码。当这些配置项设置为true时,服务器将要求客户端发送的请求内容使用指定的字符集进行编码。
另外,从 Spring Boot 2.3.5 版本开始,server.servlet.encoding.enabled配置项已被弃用。因此,推荐的做法是直接设置server.servlet.encoding.charset来指定字符集,然后通过设置server.servlet.encoding.force=true来开启对请求/响应的编码集强制控制。
2.2.2 characterEncodingFilter 方法
先来看看 characterEncodingFilter 方法的源码【】:
public CharacterEncodingFilter characterEncodingFilter() {CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();filter.setEncoding(this.properties.getCharset().name());filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));return filter;
}
上述逻辑很好理解:
-
首先,新建一个
CharacterEncodingFilter的实例对象filter。 -
然后,设置
filter的encoding属性,即编码属性。其中this.properties.getCharset().name()就是上述application.properties中的server.servlet.encoding.charset=UTF-8;如果没有配置,则默认是 UTF-8【可查看上述Encoding类】。 -
接着,设置
filter的forceRequestEncoding和forceResponseEncoding属性。我们来直接查Encoding类的shouldForce即可:public boolean shouldForce(Type type) {// Http请求,则取 server.servlet.encoding.force-request 配置// Http响应,则取 server.servlet.encoding.force-response 配置Boolean force = (type != Type.REQUEST) ? this.forceResponse : this.forceRequest;// 如果上述配置都没有if (force == null) {// 取 server.servlet.encoding.force 配置force = this.force;}if (force == null) {// 当 server.servlet.encoding.force 配置也未指定时,// 默认 强制在HTTP请求上使用配置的字符集。force = (type == Type.REQUEST);}return force; }
2.2.3 localeCharsetMappingsCustomizer 方法
话不多说,直接来看相关的源码【Spring Boot 2.7.9】
@Beanpublic LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {return new LocaleCharsetMappingsCustomizer(this.properties);}static class LocaleCharsetMappingsCustomizerimplements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {private final Encoding properties;LocaleCharsetMappingsCustomizer(Encoding properties) {this.properties = properties;}@Overridepublic void customize(ConfigurableServletWebServerFactory factory) {if (this.properties.getMapping() != null) {factory.setLocaleCharsetMappings(this.properties.getMapping());}}@Overridepublic int getOrder() {return 0;}}
上述 LocaleCharsetMappingsCustomizer 静态内部类实现了 WebServerFactoryCustomizer 接口,该接口用于自定义 Web 服务器工厂的策略接口。此类类型的任何 bean 将在服务器本身启动之前获得与服务器工厂的回调,因此您可以设置端口、地址、错误页面等。
注意:对此类接口的调用通常由
WebServerFactoryCustomizerBeanPostProcessor执行,它是一个BeanPostProcessor(在ApplicationContext生命周期中非常早期)。可能更安全的做法是在包含BeanFactory中延迟查找依赖项,而不是使用@Autowired注入它们。
而 LocaleCharsetMappingsCustomizer 类实现的 customize 方法,则用于设置自定义字符编码映射,这就不得不提 server.servlet.encoding.mapping 配置属性。
默认情况下,Spring Boot 会根据请求头的 Accept-Charset 来设置响应的字符编码。但是,有时候我们可能需要根据不同的请求路径或请求参数来进行不同的字符编码映射。这时,就可以使用 server.servlet.encoding.mapping 来实现自定义的字符编码映射。
# 当请求路径以 /en/ 开头时,将字符编码设置为 UTF-8;当请求路径以 /zh/ 开头时,将字符编码设置为 GBK。
server.servlet.encoding.mapping=/en/**=UTF-8,/zh/**=GBK
注意:
server.servlet.encoding.mapping的配置优先级高于server.servlet.encoding.charset和server.servlet.encoding.force。因此,如果同时存在多个配置项,server.servlet.encoding.mapping会覆盖其他配置项。
总结
本篇我们以 Spring Boot 内置的 http 编码功能为例来分析一下整个自动配置的过程,深入讲解了 HttpEncodingAutoConfiguration 配置类的相关内容。相信大家后续在看其他配置类,也能知其所以然了。
相关文章:
【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解
Spring Boot 源码学习系列 HttpEncodingAutoConfiguration 详解 引言往期内容主要内容1. CharacterEncodingFilter2. HttpEncodingAutoConfiguration2.1 加载自动配置组件2.2 过滤自动配置组件2.2.1 涉及注解2.2.2 characterEncodingFilter 方法2.2.3 localeCharsetMappingsCus…...
uni-app--》基于小程序开发的电商平台项目实战(七)完结篇
🏍️作者简介:大家好,我是亦世凡华、渴望知识储备自己的一名在校大学生 🛵个人主页:亦世凡华、 🛺系列专栏:uni-app 🚲座右铭:人生亦可燃烧,亦可腐败…...
手写banner切换方式
<template><!-- banner轮播切换 --><div class"banner-wrapper"><div class"banner-info"><ul class"box" ref"box"><li v-for"(item, index) in bannerList" :key"index">&…...
技术文档工具『Writerside』抢鲜体验
前言 2023 年 10 月 16 日,JetBrains 宣布以早期访问状态推出 Writerside,基于 IntelliJ 平台的 JetBrains IDE,开发人员可使用它编写、构建、测试和发布技术文档,可以作为 JetBrains IDE 中的插件使用,也可以作为独立…...
Centos磁盘爆满_openEuler系统磁盘爆满清理方法---Linux工作笔记060
磁盘爆满,监控部门就会报警,报警就要处理,但是程序员并不擅长做运维的工作,记录一下把...以后用到会方便: 使用df -h命令可以看到,对应的磁盘占用情况,这里我的/dev/mapper/openeuler-root这个目录 占用的磁盘比较多,到了百分之95了.. 往往就是这个跟目录,我这里/data目录是自…...
dubbo启动提示端口号已经被占用
本地dubbo项目启动提示: java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:132) at org.sp…...
LeetCode每日一题——2678. Number of Senior Citizens
文章目录 一、题目二、题解 一、题目 You are given a 0-indexed array of strings details. Each element of details provides information about a given passenger compressed into a string of length 15. The system is such that: The first ten characters consist o…...
按摩 推拿上门服务小程序源码 家政上门服务系统源码
按摩 推拿上门服务小程序源码 家政上门服务系统源码 上门服务系统是一款基于互联网和移动应用的高端家政服务预订平台,它集成了用户、服务员、客户三方的需求于一体,为广大市民提供方便、高效、安全、舒适的家居服务体验,让你在家当皇帝&…...
排列排序问题---2023 年华中科技大学程序设计竞赛新生赛
解析: 将序列分为多段,每段必须连续并且单调,输出段数-1即可 #include<bits/stdc.h> using namespace std; #define int long long const int N1e65; int n,a[N]; signed main(){scanf("%lld",&n);for(int i1;i<n;i)…...
数据恢复怎么做?记好这款堪比数据恢复专家的软件!
“我真的受够了数据总是莫名其妙丢失了!但是我的电脑知识又很有限,文件丢失后我都不知道应该采取什么方法来进行恢复。谁能给我介绍一些方法呀?” 数据丢失是一场噩梦,无论是因为误删除、硬盘损坏、病毒攻击还是其他原因。然而&am…...
远程监控高并发高吞吐java进程
文章目录 背景工具jconsole和jvisualvm 压测实战以太坊Java程序监控1.使用jconsole监控2.使用jvisualvm监控 问题分析堆内存使用异常通过调整内存策略来应对: 交易虚增问题 背景 作为使用java技术栈的金融类公司,确保Java程序在生产环境中的稳定性和性能…...
MapperStruct实现类为空
问题描述: MapperStruct生成的实现了为空 按照在MapperStruct官网Installation – MapStruct中的方法配置后,生成的实现了是空的,如下: Overridepublic DeployHistory toEntity(DeployHistoryDto arg0) {if ( arg0 null ) …...
【webpack】wabpack5 知识梳理
1、简单介绍 默认功能 可处理 js、json文件,处理 js 文件引入将其打包; 可处理字体、图片、音视频等静态资源(webpack5有内置loader:asset); 将es6的import规范编译为浏览器可识别的commonjs规范…...
ThinkPHP 3.2 常用内置函数
ThinkPHP 3.2 内置函数CDM疑问: D与M方法的相同点与不同点IAR 内置函数 C C方法是用于获取或修改,系统配置参数 语法: 获取:C(需要获得的配置参数Name) $value C(config_name);设置:C&…...
STM32F4_USB读卡器(USB_Slave)/USB U盘(Host)
前言 STM32F4芯片自带了USB OTG FS(FS,即全速,12Mbps)和USB OTG HS,支持USB Host和USB Device。 1. USB简介 USB,是英文Universal Serial BUS(通用串行总线)的缩写,是一…...
【网络安全入门】学习网络安全必须知道的100 个网络基础知识
前言 先领取资料再阅读哦 【282G】网络安全&黑客技术零基础到进阶全套学习大礼包(附面试题答案),免费分享! 【282G】网络安全&黑客技术零基础到进阶全套学习大礼包(附面试题答案),免…...
96核的AMD锐龙Threadripper PRO 7995WX性能如何?
AMD新推出的锐龙Threadripper 7000系列可以说是目前最快的工作站处理器,最顶级的锐龙Threadripper PRO 7995WX拥有96个Zen 4内核,共192线程,基础频率2.5GHz,加速频率5.15GHz,拥有384MB L3缓存和多达128条PCI-E 5.0通道…...
TS和JS的区别
1.TS和JS的区别 ts 是js的超集。 从执行环境上来看,浏览器、node.js 可以直接执行js,但不能执行ts;编译层面,Ts 有编译阶段,js 没有,只有转译阶段和lint阶段;ts更难写一点,但类型更安全。ts 代码写出来就是…...
顺序栈的实现----数据结构
栈的概念 对于栈(Stack),后进先出(Last In First Out,LIFO),栈也是一种线性表,只不过是一种操作受限的线性表,只能在一端操作,也就是不允许在中间进行查找、…...
k8s calico 网络原理
一、cluster ip Cluster IP 是 Kubernetes 中 Service 的 IP 地址,它是一个虚拟 IP 地址,用于集群内的 Pod 相互通信。 例如: Cluster IP:2.2.2.2负载的真实Pod IP:1.1.1.1 场景: Pod A 的 IP 地址是 …...
《Qt C++ 与 OpenCV:解锁视频播放程序设计的奥秘》
引言:探索视频播放程序设计之旅 在当今数字化时代,多媒体应用已渗透到我们生活的方方面面,从日常的视频娱乐到专业的视频监控、视频会议系统,视频播放程序作为多媒体应用的核心组成部分,扮演着至关重要的角色。无论是在个人电脑、移动设备还是智能电视等平台上,用户都期望…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
Java多线程实现之Thread类深度解析
Java多线程实现之Thread类深度解析 一、多线程基础概念1.1 什么是线程1.2 多线程的优势1.3 Java多线程模型 二、Thread类的基本结构与构造函数2.1 Thread类的继承关系2.2 构造函数 三、创建和启动线程3.1 继承Thread类创建线程3.2 实现Runnable接口创建线程 四、Thread类的核心…...
分布式增量爬虫实现方案
之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面,避免重复抓取,以节省资源和时间。 在分布式环境下,增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路:将增量判…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...
嵌入式学习笔记DAY33(网络编程——TCP)
一、网络架构 C/S (client/server 客户端/服务器):由客户端和服务器端两个部分组成。客户端通常是用户使用的应用程序,负责提供用户界面和交互逻辑 ,接收用户输入,向服务器发送请求,并展示服务…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
AI语音助手的Python实现
引言 语音助手(如小爱同学、Siri)通过语音识别、自然语言处理(NLP)和语音合成技术,为用户提供直观、高效的交互体验。随着人工智能的普及,Python开发者可以利用开源库和AI模型,快速构建自定义语音助手。本文由浅入深,详细介绍如何使用Python开发AI语音助手,涵盖基础功…...
