配置类(一般都是只读文件)的好处:众所周知,SSM框架中各种复杂的配置让其得到配置地狱这一称号,而sprint boot框架避免了手写繁琐的XML文件,不用自己配置,一切springboot都帮我们配置好了。
IDEA中为何在application.properties中写上
spring.http.encoding.charset= us-ascii
时可以自动将默认的UTF-8编码改成us-ascii编码呢?本文源码分析这个自动装配功能是怎么实现的。
首先我们在IDEA中找到实现该功能的配置类
步骤如下:
1、
在IDEA中用Maven创立一个springboot项目后点击External Libraries
2,在META-INF下找到spring.factories文件
3,打开spring.factories并找到Auto Configure注释,其后声明了所有第三方依赖
功能解释:spring boot在启动时会根据META-INF/spring factories找到文件中的第三方依赖并自动配置,所以这是不用自己手写第三方依赖XML文件从而避免繁琐的原因
4,那么spring.factories中声明的第三方依赖在哪里呢?如图箭头所示,第三方依赖放在和META-INF同级的一个包中,这是整个J2EE整合体系所需的依赖
5,点击org.springframework.boot.autoconfugue,可以看到很多不同种类的依赖包
6,本文是解释字符编码自动配置原理,字符编码是属于web功能的,所以我们要找到web依赖包,并找到配置类HttpEncodeingAutoConfiguration.class并打开
7, 找到@EnableConfigurationProperties的注解
下面是 HttpProperties.class源码:
// Source code recreated from a .class file by IntelliJ IDEA (翻译:由IntelliJ IDEA从.class文件重新创建的源代码,说明这个不是spring boot官方源代码)
// (powered by Fernflower decompiler) (翻译:由Fernflower反编译器提供动力,人间迷惑行为有木有?)
//
package org.springframework.boot.autoconfigure.http;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(
prefix = "spring.http" //prefix前缀,在application.properties中可通过前缀调用
)
public class HttpProperties {
private boolean logRequestDetails;
private final HttpProperties.Encoding encoding = new HttpProperties.Encoding();
//HttpProperties.Encoding表示调用静态内部类Encoding生成一个静态内部类对象encoding
public HttpProperties() { //HttpProperties类的无参构造方法
}
public boolean isLogRequestDetails() {
return this.logRequestDetails;
}
public void setLogRequestDetails(boolean logRequestDetails) {
this.logRequestDetails = logRequestDetails;
}
public HttpProperties.Encoding getEncoding() {
return this.encoding;
}
public static class Encoding { //HttpProperties的静态内部类Encoding
public static final Charset DEFAULT_CHARSET;//PS:JAVA中所有被 final 修饰的量都是常量 也就是该量的值是不变的,用static主要作用是在类刚加载时就初始化该量的值并给他分配一块共用的内存块存储他的值。
private Charset charset;//声明一个private可见的Charset类型的变量,变量名为charset;
private Boolean force;
private Boolean forceRequest;
private Boolean forceResponse;
private Map<Locale, Charset> mapping;
public Encoding() {//静态内部类Encoding的无参构造方法将本类的charset变量赋值为DEFAULT_CHARSET
this.charset = DEFAULT_CHARSET;
}
public Charset getCharset() {
return this.charset;
}
public void setCharset(Charset charset) {
this.charset = charset;
}
public boolean isForce() {
return Boolean.TRUE.equals(this.force);
}
public void setForce(boolean force) {
this.force = force;
}
public boolean isForceRequest() {
return Boolean.TRUE.equals(this.forceRequest);
}
public void setForceRequest(boolean forceRequest) {
this.forceRequest = forceRequest;
}
public boolean isForceResponse() {
return Boolean.TRUE.equals(this.forceResponse);
}
public void setForceResponse(boolean forceResponse) {
this.forceResponse = forceResponse;
}
public Map<Locale, Charset> getMapping() {
return this.mapping;
}
public void setMapping(Map<Locale, Charset> mapping) {
this.mapping = mapping;
}
public boolean shouldForce(HttpProperties.Encoding.Type type) {
Boolean force = type != HttpProperties.Encoding.Type.REQUEST ? this.forceResponse : this.forceRequest;
if (force == null) {
force = this.force;
}
if (force == null) {
force = type == HttpProperties.Encoding.Type.REQUEST;
}
return force;
}
static {
DEFAULT_CHARSET = StandardCharsets.UTF_8;//(后面StandardCharsets类的源码,此处使用了 StandardCharsets类的静态常量UTF_8)
}
//PS:静态语句块:static{}(即static块),会在类被加载的时候执行且仅会被执行一次,一般用来初始化静态变量和调用静态方法
public static enum Type {
REQUEST,
RESPONSE;
private Type() {
}
}
}
}
StandardCharsets.class源码(非IDEA重写的官方源码):
此类含有各种字符集静态常量
第一段注释翻译:
标准{@link Charset字符集}的常量定义。这些字符集保证在Java平台的每个实现上都可用。
/**
* Constant definitions for the standard {@link Charset Charsets}. These
* charsets are guaranteed to be available on every implementation of the Java
* platform.
*
* @see <a href="Charset#standard">Standard Charsets</a>
* @since 1.7
*/
public final class StandardCharsets { //当用final修饰一个类时,表明这个类不能被继承
private StandardCharsets() {
throw new AssertionError("No java.nio.charset.StandardCharsets instances for you!");
}
//private修饰构造方法表明当外部new一个StandardCharsets对象时会抛出AssertionError异常
/**
* Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the
* Unicode character set
*/
public static final Charset US_ASCII = Charset.forName("US-ASCII");
/**
* ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1
*/
public static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
/**
* Eight-bit UCS Transformation Format
*/
public static final Charset UTF_8 = Charset.forName("UTF-8");
/**
* Sixteen-bit UCS Transformation Format, big-endian byte order
*/
public static final Charset UTF_16BE = Charset.forName("UTF-16BE");
/**
* Sixteen-bit UCS Transformation Format, little-endian byte order
*/
public static final Charset UTF_16LE = Charset.forName("UTF-16LE");
/**
* Sixteen-bit UCS Transformation Format, byte order identified by an
* optional byte-order mark
*/
public static final Charset UTF_16 = Charset.forName("UTF-16");
}
最后总结一下
的完整内部调用过程:
1,spring.http为前缀,使用它相当于调用HttpProperties类
2,spring.http.encoding相当于调用HttpProperties类的静态encoding方法
3,spring.http.encoding.charset相当于调用HttpProperties类的静态encoding方法的charset变量
4,最后一步给charset变量赋字符集