源码学习系列之SpringBoot自动配置(篇二)
源码学习系列之SpringBoot自动配置(篇二)之HttpEncodingAutoConfiguration 源码分析
继上一篇博客源码学习系列之SpringBoot自动配置(篇一)之后,本博客继续跟一下SpringBoot的自动配置源码
ok,先复习一下上一篇的内容,从前面的学习,我们知道了SpringBoot的自动配置主要是由一个选择器AutoConfigurationImportSelector,先通过选择器将自动配置的类加载到Spring容器
注意点:
List configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
获取的候选配置的类名- 由SpringFactoriesLoader加载器负责加载配置类名,已经装载配置类到容器,SpringFactoriesLoader的loadSpringFactories方法读取自动配置工程的META-INF/spring.factories配置文件,加载配置类的全类名,包装成Properties对象,然后再加载到容器里
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
/* 将spring.factories的类都装载到Spring容器*/
public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
try {
//将META-INF/spring.factories文件里配置的属性都装载到Enumeration数据结构里
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
ArrayList result = new ArrayList();
//遍历获取属性,然后再获取对应的配置类全类名
while(urls.hasMoreElements()) {
URL url = (URL)urls.nextElement();
Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
String factoryClassNames = properties.getProperty(factoryClassName);
result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
}
return result;
} catch (IOException var8) {
throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() + "] factories from location [" + "META-INF/spring.factories" + "]", var8);
}
}
ok,Springboot的自动配置类都在这个包里,源码很多,所以本博客只是简单跟一下源码
自动配置可以说是SpringBoot框架的一个很重要的功能,其强大的功能就是通过很多配置类实现的,当然这么多配置,可以参考SpringBoot官方的配置参考:
https://docs.spring.io/spring-boot/docs/2.1.10.RELEASE/reference/html/common-application-properties.html
SpringBoot的自动配置类很多,显然不是每个配置类都生效的,比如你没引对应的jar,那对应的配置类肯定是不起效的,ok,本博客以HttpEncodingAutoConfiguration自动编码配置类为实例,记录一下SpringBoot的自动配置
先补充一些@Conditional注解的用法:详情可以参考我上篇博客SpringBoot系列之@Conditional注解用法简介
@Conditional派生注解 | 作用(都是判断是否符合指定的条件) |
---|---|
@ConditionalOnJava | 系统的java版本是否符合要求 |
@ConditionalOnBean | 有指定的Bean类 |
@ConditionalOnMissingBean | 没有指定的bean类 |
@ConditionalOnExpression | 符合指定的SpEL表达式 |
@ConditionalOnClass | 有指定的类 |
@ConditionalOnMissingClass | 没有指定的类 |
@ConditionalOnSingleCandidate | 容器只有一个指定的bean,或者这个bean是首选bean |
@ConditionalOnProperty | 指定的property属性有指定的值 |
@ConditionalOnResource | 路径下存在指定的资源 |
@ConditionalOnWebApplication | 系统环境是web环境 |
@ConditionalOnNotWebApplication | 系统环境不是web环境 |
@ConditionalOnjndi | JNDI存在指定的项 |
通过上篇博客的学习,我们已经知道了SpringBoot有很多自动配置类,所以本博客拿HttpEncodingAutoConfiguration类来看看
补充:
- @Configuration proxyBeanMethods属性:默认是开启的,开启后允许其它配置类调用这个类的@bean方法,详情参看Spring官方文档:Spring官方文档
package org.springframework.boot.autoconfigure.web.servlet;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.http.HttpProperties;
import org.springframework.boot.autoconfigure.http.HttpProperties.Encoding;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.boot.web.servlet.filter.OrderedCharacterEncodingFilter;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.filter.CharacterEncodingFilter;
@Configuration(
proxyBeanMethods = false
)//指定是一个配置列,关了proxyBeanMethods,其它配置类就不能调相应的@bean类
@EnableConfigurationProperties({HttpProperties.class})//让使用 @ConfigurationProperties注解的HttpProperties类生效,HttpProperties类通过ConfigurationProperties注解,将属性配置一个一个加载进来
@ConditionalOnWebApplication(
type = Type.SERVLET
)//指定系统环境是Web环境配置才起效,并且指定类型是SERVLET
@ConditionalOnClass({CharacterEncodingFilter.class})//系统有CharacterEncodingFilter过滤器类,则配置类起效,CharacterEncodingFilter类:SpringMVC中进行乱码解决的过滤器
@ConditionalOnProperty(
prefix = "spring.http.encoding",
value = {"enabled"},
matchIfMissing = true
)//判断配置文件是否有spring.http.encoding.enabled属性,如果没配置,也是默认为true的,因为配置了`matchIfMissing =true`
public class HttpEncodingAutoConfiguration {
//创建一个Encoding对象
private final Encoding properties;
// 构造函数里通过properties.getEncoding();进行属性映射,获取默认的配置
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean
@ConditionalOnMissingBean//如果系统没有CharacterEncodingFilter类,就执行characterEncodingFilter方法
public CharacterEncodingFilter characterEncodingFilter() {
//重新创建一个编码过滤器
OrderedCharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
//设置默认的配置
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(org.springframework.boot.autoconfigure.http.HttpProperties.Encoding.Type.RESPONSE));
return filter;
}
@Bean
public HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer localeCharsetMappingsCustomizer() {
return new HttpEncodingAutoConfiguration.LocaleCharsetMappingsCustomizer(this.properties);
}
private static class LocaleCharsetMappingsCustomizer implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>, Ordered {
private final Encoding properties;
LocaleCharsetMappingsCustomizer(Encoding properties) {
this.properties = properties;
}
public void customize(ConfigurableServletWebServerFactory factory) {
if(this.properties.getMapping() != null) {
factory.setLocaleCharsetMappings(this.properties.getMapping());
}
}
public int getOrder() {
return 0;
}
}
}
通过对HttpEncodingAutoConfiguration源码的学习,可以看出,其实主要是用@Conditional及其派生注解,这些注解都是要在特定情况才会起效,起效了,才会将组件加载到Spring容器里
ok,然后我们怎么知道哪些配置是起效的?在SpringBoot项目里,是可以通过配置,开启打印的,可以在application.properties加上debug=true
属性就可以
控制台打印的Positive matches就表示有效的配置类
console打印的Negative matches表示不起效的配置类:
比如我的项目没有加aop的,aop自动配置类就不起效
源码学习系列之SpringBoot自动配置(篇二)的更多相关文章
- 源码学习系列之SpringBoot自动配置(篇一)
源码学习系列之SpringBoot自动配置源码学习(篇一) ok,本博客尝试跟一下Springboot的自动配置源码,做一下笔记记录,自动配置是Springboot的一个很关键的特性,也容易被忽略的属 ...
- SpringBoot源码学习系列之SpringMVC自动配置
目录 1.ContentNegotiatingViewResolver 2.静态资源 3.自动注册 Converter, GenericConverter, and Formatter beans. ...
- SpringBoot源码学习系列之异常处理自动配置
SpringBoot源码学习系列之异常处理自动配置 1.源码学习 先给个SpringBoot中的异常例子,假如访问一个错误链接,让其返回404页面 在浏览器访问: 而在其它的客户端软件,比如postm ...
- SpringBoot源码学习系列之Locale自动配置
目录 1.spring.messages.cache-duration 2.LocaleResolver 的方法名必须为localeResolver 3.默认LocaleResolver 4.指定默认 ...
- SpringBoot源码学习系列之嵌入式Servlet容器
目录 1.博客前言简单介绍 2.定制servlet容器 3.变换servlet容器 4.servlet容器启动原理 SpringBoot源码学习系列之嵌入式Servlet容器启动原理 @ 1.博客前言 ...
- Spring5.0源码学习系列之事务管理概述
Spring5.0源码学习系列之事务管理概述(十一),在学习事务管理的源码之前,需要对事务的基本理论比较熟悉,所以本章节会对事务管理的基本理论进行描述 1.什么是事务? 事务就是一组原子性的SQL操作 ...
- Spring5.0源码学习系列之浅谈BeanFactory创建
Spring5.0源码学习系列之浅谈BeanFactory创建过程 系列文章目录 提示:Spring源码学习专栏链接 @ 目录 系列文章目录 博客前言介绍 一.获取BeanFactory主流程 二.r ...
- Java并发包源码学习系列:阻塞队列BlockingQueue及实现原理分析
目录 本篇要点 什么是阻塞队列 阻塞队列提供的方法 阻塞队列的七种实现 TransferQueue和BlockingQueue的区别 1.ArrayBlockingQueue 2.LinkedBloc ...
- JDK源码学习系列05----LinkedList
JDK源码学习系列05----LinkedList 1.LinkedList简介 LinkedList是基于双向链表实 ...
随机推荐
- Spring Boot2 系列教程(十二)@ControllerAdvice 的三种使用场景
严格来说,本文并不算是 Spring Boot 中的知识点,但是很多学过 SpringMVC 的小伙伴,对于 @ControllerAdvice 却并不熟悉,Spring Boot 和 SpringM ...
- 2018 php 面试
排序算法 快速排序 快速排序是十分常用的高效率的算法,其思想是:先选一个标尺,用它把整个队列过一遍筛选,以保证左边的元素都不大于它,其右边都不小于它 function quickSort($arr){ ...
- MySQL学习(一)索引的基本认识
MySQL中,所有的数据类型都可以被索引,包括普通索引,唯一性索引,全文索引,单列索引,多列索引和空间索引等. 额外的:我已知的自动创建索引的时机:创建主键,唯一,外键约束的时候 一.索引简介 1.1 ...
- 攻防世界(XCTF)WEB(进阶区)write up(一)
cat ics-05 ics-06 lottery Cat XCTF 4th-WHCTF-2017 输入域名 输入普通域名无果 输入127.0.0.1返回了ping码的结果 有可能是命令执行 ...
- CVE-2019-0708(非蓝屏poc)远程桌面代码执行漏洞复现
玩了几天 刚回成都 玩电脑复现一下~ 内核漏洞原理暂时 没看懂 别问 ,问就是不懂 0x01 复现环境和Exp准备 漏洞影响范围 Windows 7 Windows Server 2008 R2 W ...
- CDN实现原理
避让:尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快.更稳定. 检测:通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时监 ...
- mysql 二十余种报错注入姿势
1.floor() floor 和group by 搭配使用 利用group by 的key唯一性 和mysql 编码执行顺序导致二次执行产生不同key ))) ) 数值型注入时 不用闭合‘ 进行 ...
- Arduino学习笔记⑤ 模拟IO实验
1.前言 还记得前几个我们都是在讲解数字IO,而其实我们生活中大多数信号都是模拟信号,如声音以及温度变化.在Arduino中,常用0~5v的电压来表示模拟信号. 1.1 模拟输入功能 ...
- CocosCreator中_worldMatrix到底是什么(下)
Cocos Creator 中 _worldMatrix 到底是什么(下) 1. 摘要 上篇介绍了矩阵的基本知识以及对应图形变换矩阵推倒.中篇具体介介绍了对应矩阵转换成cocos creator代码的 ...
- js检测页面上一个元素是否已经滚动到了屏幕的可视区域内
应用场景:只要页面加载了,其中在页面中出现的li就向控制台输出第几个发送请求:在本次加载的页面中,再将滚动条滚回前边的li,不再向控制台输出东西,也就是说已经显示过的li,不再向控制台输出东西. &l ...