-
首先,我们创建一个springboot项目会自动创建一个入口类xxxApplication
我们通过入口类上的注解@SpringBootApplication的子注解,开启自动配置功能
通过AutoConfigurationImportSelector,导入需要自动配置的类,下面我们打开AutoConfigurationImportSelector源码一探究竟。
-
AutoConfigurationImportSelector.class源码
AutoConfigurationImportSelector中的重要方法:
- process方法详解【在该方法中调getAutoConfigurationEntry()方法来得到自动配置类放入autoConfigurationEntry对象中】
// 这里用来处理自动配置类,比如过滤掉不符合匹配条件的自动配置类
// 由自动配置逻辑相关的入口方法DeferredImportSelectorGrouping类的getImports方法调用
// annotationMetadata:元数据信息
// deferredImportSelector:具体类型为AutoConfigurationImportSelector
@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
// 【1】deferredImportSelector强转为具体的AutoConfigurationImportSelector类型,
// 并调用getAutoConfigurationEntry方法得到自动配置类放入autoConfigurationEntry对象中
AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
.getAutoConfigurationEntry(getAutoConfigurationMetadata(), annotationMetadata);
// 【2】又将封装了自动配置类的autoConfigurationEntry对象撞见autoConfigurationEntries集合
this.autoConfigurationEntries.add(autoConfigurationEntry);
// 【3】遍历刚刚获取的自动配置类
for (String importClassName : autoConfigurationEntry.getConfigurations()) {
// 这里将符合条件的自动配置类作为key,annotationMetadata作为值存放金enrties集合
this.entries.putIfAbsent(importClassName, annotationMetadata);
}
}
- getAutoConfigurationEntry()方法详解
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
// 【1】得到spring.factories文件配置的所有的自动配置类
List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
// 利用LinkedHashSet移除重复的配置类【不同的spring.factories中配置了相同的自动配置类】
configurations = removeDuplicates(configurations);
// 得到要排除的自动配置类,比如注解属性exclude的配置类
// 比如:@SpringBootApplication(exclude= FreeMarkerAutoConfiguration.class)
// 将会获取到exclude = FreeMarkerAutoConfiguration.class的元注解数据
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
// 检查要被排除的配置类,因为有些不是自动配置类,故要抛出异常
checkExcludedClasses(configurations, exclusions);
// 【2】将要排除的配置类移除
configurations.removeAll(exclusions);
// 【3】因为从spring.factories文件获取的自动配置类太多。如果有些不必要的自动配置类都加载进内存,会造成内存浪费。
// 因此将一些不必要的配置类移除
configurations = filter(configurations, autoConfigurationMetadata);
// 【4】获取了符合条件的自动配置类后,此时触发AutoConfigurationImportEvent事件
// 目的是告诉ConditionEvaluationReport条件评估报告器对象来记录符合条件的自动配置类
fireAutoConfigurationImportEvents(configurations, exclusions);
// 【5】将符合条件和要排除的自动配置类封装进AutoConfigurationEntry对象
return new AutoConfigurationEntry(configurations, exclusions);
}
- 自动配置入口方法:【在该方法中调用了process()与selectImports()两个主要方法】
process()方法上面已经详细讲解了,下面看一下selectImport()方法
selectImport()方法详解:
@Override
public Iterable<Entry> selectImports() {
// 这里得到所有要排除的自动配置类的set集合
Set<String> allExclusions = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getExclusions).flatMap(Collection::stream).collect(Collectors.toSet());
// 这里得到经过滤后符合条件的自动配置类的set集合
Set<String> processedConfigurations = this.autoConfigurationEntries.stream()
.map(AutoConfigurationEntry::getConfigurations).flatMap(Collection::stream)
.collect(Collectors.toCollection(LinkedHashSet::new));
// 移除掉要排除的自动配置类【exclude】
processedConfigurations.removeAll(allExclusions);
// 将标有@Order注解的自动配置类进行排序
return sortAutoConfigurations(processedConfigurations, getAutoConfigurationMetadata()).stream()
.map((importClassName) -> new Entry(this.entries.get(importClassName), importClassName))
.collect(Collectors.toList());
}
下面我们以一个springboot帮我自动配置的类,进行演示:
使用过ssm框架的小伙伴们大概都有这样一个疑问,之前我们使用ssm框架的时候都要在web.xml文件中配置一个Filter用来处理post请求的乱码问题,但是使用springnboot却不会发生这种问题。
这是为什么呢?答案:因为springboot帮助我们自动配置了编码为UTF-8
HttpEncodingAutoConfiguration:这个类,用于帮助我们解决post请求的乱码问题。
HttpEncodingAutoConfiguration源码【详解】:
//表示这是一个配置类,和以前编写的配置文件一样,也可以给容器中添加组件
@Configuration(proxyBeanMethods = false)
//启动指定类【HttpProperties】的ConfigurationProperties功能:将配置文件中对应的值和HttpEncodingProperties绑定起来
@EnableConfigurationProperties(HttpProperties.class)
//spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效。
//判断当前应用是否是web应用,如果是,当前配置类生效
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
//判断当前项目中有没有这个CharacterEncodingFilter:springmvc中解决乱码的乱码的过滤器
@ConditionalOnClass(CharacterEncodingFilter.class)
//判断配置文件中是否存在某个配置 spring.http.encoding.enabled 如果不存在,判断也是成立的
//matchIfMissing=true 表示即使我们配置文件中不配置spring.http.encoding.enabled=true 也是默认生效的
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
// 它已经和springboot配置文件中的值进行映射了
private final HttpProperties.Encoding properties;
// 只有有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpProperties properties) {
this.properties = properties.getEncoding();
}
@Bean //给容器添加一个组件,这个组件中的某些值需要从properties中获取
@ConditionalOnMissingBean //判断容器中有没有这个组件
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}