【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解

这篇具有很好参考价值的文章主要介绍了【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Spring Boot 源码学习系列

【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解,开发框架-Spring Boot,Spring Boot,源码学习,Http编码配置类,自定义字符编码映射

引言

前面的博文,我们从源码角度介绍了自动装配流程。虽然带大家从整体上有了清晰的认识,但是我们还不能熟练地运用。本篇就以 Spring Boot 内置的 http 编码功能为例,来带大家分析一下 HttpEncodingAutoConfiguration 的整个自动配置的过程。

【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解,开发框架-Spring Boot,Spring Boot,源码学习,Http编码配置类,自定义字符编码映射

往期内容

在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】:

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 项目中,Springweb 开发提供的一个过滤器【即 org.springframework.web.filter.CharacterEncodingFilter 】,用来防止 web 开发中出现的乱码问题,它是 Spring 通过在 web 请求中定义 requestresponse 的编码来实现。

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 源码学习】HttpEncodingAutoConfiguration 详解,开发框架-Spring Boot,Spring Boot,源码学习,Http编码配置类,自定义字符编码映射

实际上 在 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 中。

【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解,开发框架-Spring Boot,Spring Boot,源码学习,Http编码配置类,自定义字符编码映射

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

显然这里涉及到了 ConditionalOnClassConditionalOnWebApplication 注解,我们翻看 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
	@ConditionalOnMissingBean
	public CharacterEncodingFilter characterEncodingFilter() {
		//  。。。
	}

	@Bean
	public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
		// 。。。
	}
	
	// ...
}
2.2.1 涉及注解

我们先来看看上述 HttpEncodingAutoConfiguration 配置类涉及到的注解,如下:

  • @AutoConfiguration : 该类是一个自动配置类,Spring Boot 会根据项目中的依赖自动配置这个类的实例。
  • @EnableConfigurationProperties(ServerProperties.class) :启用 ServerProperties 类的配置属性,这样在配置文件中就可以使用 server.servlet.encoding 属性来配置字符编码。
  • @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET) :该配置类只有在基于 servletweb 应用程序中才会被实例化。
  • @ConditionalOnClass(CharacterEncodingFilter.class) :只有在项目中存在 CharacterEncodingFilter 类时才会生效。
  • @ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true) :只有在配置文件中 server.servlet.encoding 属性的值为 "enabled" 时才会生效;当然如果配置文件中没有这个属性,也默认会生效。
  • @Bean :用于声明一个方法创建的对象是一个 Spring 管理的 BeanSpring 容器会自动管理这个 Bean 的生命周期,包括依赖注入、初始化和销毁等。
  • @ConditionalOnMissingBean :只有在当前 Spring 容器中不存在指定类型的 Bean 时,才会执行被注解的方法。这样可以用于确保在需要的时候才创建某个 Bean,避免重复创建。

其中 ServerProperties 类的属性值对应着 application.ymlapplication.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 {
		// 。。。
		@NestedConfigurationProperty
		private 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=trueserver.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.3 characterEncodingFilter 方法

先来看看 characterEncodingFilter 方法的源码【Spring Boot 2.7.9】:

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

  • 然后,设置 filterencoding 属性,即编码属性。其中 this.properties.getCharset().name() 就是上述 application.properties 中的 server.servlet.encoding.charset=UTF-8;如果没有配置,则默认是 UTF-8【可查看上述 Encoding 类】。

  • 接着,设置 filterforceRequestEncodingforceResponseEncoding 属性。我们来直接查 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.4 localeCharsetMappingsCustomizer 方法

话不多说,直接来看相关的源码【Spring Boot 2.7.9

	@Bean
	public LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
		return new LocaleCharsetMappingsCustomizer(this.properties);
	}

	static class LocaleCharsetMappingsCustomizer
			implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {

		private final Encoding properties;

		LocaleCharsetMappingsCustomizer(Encoding properties) {
			this.properties = properties;
		}

		@Override
		public void customize(ConfigurableServletWebServerFactory factory) {
			if (this.properties.getMapping() != null) {
				factory.setLocaleCharsetMappings(this.properties.getMapping());
			}
		}

		@Override
		public 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.charsetserver.servlet.encoding.force。因此,如果同时存在多个配置项,server.servlet.encoding.mapping 会覆盖其他配置项。

总结

本篇我们以 Spring Boot 内置的 http 编码功能为例来分析一下整个自动配置的过程,深入讲解了 HttpEncodingAutoConfiguration 配置类的相关内容。相信大家后续在看其他配置类,也能知其所以然了。文章来源地址https://www.toymoban.com/news/detail-717226.html

到了这里,关于【Spring Boot 源码学习】HttpEncodingAutoConfiguration 详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Spring Boot 源码学习】OnWebApplicationCondition 详解

    《Spring Boot 源码学习系列》 上篇博文带大家从 Spring Boot 源码深入详解了 OnBeanCondition ,那本篇也同样从源码入手,带大家深入了解 OnWebApplicationCondition 的过滤匹配实现。 在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,欢迎关注系列专栏】: Spr

    2024年02月08日
    浏览(38)
  • 【Spring Boot 源码学习】自动装配流程源码解析(上)

    《Spring Boot 源码学习系列》 上篇博文,笔者带大家从整体上了解了AutoConfigurationImportSelector 自动装配逻辑的核心功能及流程,由于篇幅有限,更加细化的功能及流程详解还没有介绍。本篇开始将从其源码入手,重点解析细化后的自动装配流程源码。 在开始本篇的内容介绍之前

    2024年02月14日
    浏览(41)
  • 【Spring Boot 源码学习】自动装配流程源码解析(下)

    《Spring Boot 源码学习系列》 上篇博文,笔者带大家了解了自动装配流程中有关自动配置加载的流程; 本篇将介绍自动装配流程剩余的内容,包含了自动配置组件的排除和过滤、触发自动配置事件。 在开始本篇的内容介绍之前,我们先来看看往期的系列文章【有需要的朋友,

    2024年02月11日
    浏览(36)
  • 【Spring Boot 源码学习】深入 FilteringSpringBootCondition

    Spring Boot 源码学习系列 前两篇博文笔者带大家从源码深入了解了 Spring Boot 的自动装配流程,其中自动配置过滤的实现由于篇幅限制,还未深入分析。 那么从本篇开始,Huazie 就带大家走近 AutoConfigurationImportFilter ,一起从源码解析 FilteringSpringBootCondition 、 OnBeanCondition 、 OnCl

    2024年02月09日
    浏览(40)
  • 【Spring Boot 源码学习】走近 AutoConfigurationImportSelector

    《Spring Boot 源码学习系列》 上篇博文我们了解了 @EnableAutoConfiguration 注解,其中真正实现自动配置功能的核心实现者 AutoConfigurationImportSelector 还没有详细说明,本篇将从它的源码入手来重点介绍。 在介绍 AutoConfigurationImportSelector 之前,有必要了解下它所实现的 ImportSelector 接

    2024年02月12日
    浏览(29)
  • 【Spring Boot 源码学习】初识 SpringApplication

    《Spring Boot 源码学习系列》 往期的博文, Huazie 围绕 Spring Boot 的核心功能,带大家从总整体上了解 Spring Boot 自动配置的原理以及自动配置核心组件的运作过程。这些内容大家需要重点关注,只有了解这些基础的组件和功能,我们在后续集成其他三方类库的 Starters 时,才能够

    2024年02月05日
    浏览(39)
  • 【Spring Boot 源码学习】@Conditional 条件注解

    《Spring Boot 源码学习系列》 前面的博文,Huazie 带大家从 Spring Boot 源码深入了解了自动配置类的读取和筛选的过程,然后又详解了 OnClassCondition 、 OnBeanCondition 、 OnWebApplicationCondition 这三个自动配置过滤匹配子类实现。 在上述的博文中,我们其实已经初步涉及到了像 @Conditi

    2024年02月07日
    浏览(41)
  • 【Spring Boot 源码学习】BootstrapContext的实际使用场景

    《Spring Boot 源码学习系列》 上一篇博文《BootstrapRegistry 初始化器实现》, Huazie 向大家介绍了如何自定义 BootstrapRegistryInitializer 接口实现,并以此来执行自定义的初始化操作【如注册自定义的 Bean 、添加 BootstrapContext 关闭监听器】。其中涉及到了 BootstrapContext 的部分使用场景

    2024年03月11日
    浏览(46)
  • 【Spring Boot 源码学习】SpringApplication 的定制化介绍

    《Spring Boot 源码学习系列》 前面的博文, Huazie 带大家从 Spring Boot 的启动类 SpringApplication 上入手,了解了 SpringApplication 的实例化过程。这实例化构造过程中包含了各种初始化的操作,都是 Spring Boot 默认配置的。如果我们需要定制化配置, SpringApplication 也提供了相关的入口

    2024年01月25日
    浏览(35)
  • java版本企业电子招标采购系统源码Spring Cloud + Spring Boot +二次开发

      java版本企业电子招标采购系统源码Spring Cloud + Spring Boot +二次开发   一、立项管理 1、招标立项申请 功能点:招标类项目立项申请入口,用户可以保存为草稿,提交。 2、非招标立项申请 功能点:非招标立项申请入口、用户可以保存为草稿、提交。 3、采购立项列表 功能点

    2024年02月06日
    浏览(60)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包