【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.factories
META-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 地址是 …...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案
JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停 1. 安全点(Safepoint)阻塞 现象:JVM暂停但无GC日志,日志显示No GCs detected。原因:JVM等待所有线程进入安全点(如…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...

基于Springboot+Vue的办公管理系统
角色: 管理员、员工 技术: 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能: 该办公管理系统是一个综合性的企业内部管理平台,旨在提升企业运营效率和员工管理水…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...

Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...

【若依】框架项目部署笔记
参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作: 压缩包下载:http://download.redis.io/releases 1. 上传压缩包,并进入压缩包所在目录,解压到目标…...