springboot自动配置流程

本文介绍了SpringBoot自动配置的工作原理,通过分析`AutoConfigurationImportSelector`类,揭示了自动配置类的加载过程。特别地,文章以`HttpEncodingAutoConfiguration`为例,详细解释了这个类如何解决POST请求的乱码问题,展示了SpringBoot如何简化了与SSM框架相比的编码设置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 首先,我们创建一个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;
	}

出现这个错误的原因是在导入seaborn包时,无法从typing模块中导入名为'Protocol'的对象。 解决这个问题的方法有以下几种: 1. 检查你的Python版本是否符合seaborn包的要求,如果不符合,尝试更新Python版本。 2. 检查你的环境中是否安装了typing_extensions包,如果没有安装,可以使用以下命令安装:pip install typing_extensions。 3. 如果你使用的是Python 3.8版本以下的版本,你可以尝试使用typing_extensions包来代替typing模块来解决该问题。 4. 检查你的代码是否正确导入了seaborn包,并且没有其他导入错误。 5. 如果以上方法都无法解决问题,可以尝试在你的代码中使用其他的可替代包或者更新seaborn包的版本来解决该问题。 总结: 出现ImportError: cannot import name 'Protocol' from 'typing'错误的原因可能是由于Python版本不兼容、缺少typing_extensions包或者导入错误等原因造成的。可以根据具体情况尝试上述方法来解决该问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [ImportError: cannot import name ‘Literal‘ from ‘typing‘ (D:\Anaconda\envs\tensorflow\lib\typing....](https://blog.youkuaiyun.com/yuhaix/article/details/124528628)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值