Spring Boot2 源码 run prepareEnvironment方法 (三)

2024-04-01 22:08

本文主要是介绍Spring Boot2 源码 run prepareEnvironment方法 (三),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

6、根据运行监听器和应用参数来准备 Spring 环境 

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environmentConfigurableEnvironment environment = getOrCreateEnvironment();configureEnvironment(environment, applicationArguments.getSourceArgs());listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}

 getOrCreateEnvironment初始化运行环境 this.webApplicationType=SERVLET 在前面讲过会在SpringApplication初始化赋值,所以运行环境是StandardServletEnvironment

private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;}switch (this.webApplicationType) {case SERVLET:return new StandardServletEnvironment();case REACTIVE:return new StandardReactiveWebEnvironment();default:return new StandardEnvironment();}}

listeners.environmentPrepared(environment);发布org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent事件 见(ApplicationStartingEvent)事件 不在赘述

ConfigFileApplicationListener该类赋值读取文件

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();postProcessors.add(this);AnnotationAwareOrderComparator.sort(postProcessors);for (EnvironmentPostProcessor postProcessor : postProcessors) {postProcessor.postProcessEnvironment(event.getEnvironment(),event.getSpringApplication());}}

postProcessors.add(this);将自己也加入list中,循环调用postProcessEnvironment方法,先只看ConfigFileApplicationListener类的

Loader内部类将this.propertySourceLoaders 赋值

org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader

循环加载器获取文件,注意在加载EnvironmentPostProcessor实现类是有顺序的,也就是说后面的属性会覆盖前面文件的属性,还记得postProcessors.add(this)么,也就是说最后才会加载ConfigFileApplicationListener,将本项目中的配置文件替换前面配置文件的属性,然后在看下本项目的加载依次的顺序如下: 

1.PropertiesPropertySourceLoader "properties", "xml"   2.YamlPropertySourceLoader "yml", "yaml" 

private void load(String location, String name, Profile profile,DocumentFilterFactory filterFactory, DocumentConsumer consumer) {if (!StringUtils.hasText(name)) {for (PropertySourceLoader loader : this.propertySourceLoaders) {if (canLoadFileExtension(loader, location)) {load(loader, location, profile,filterFactory.getDocumentFilter(profile), consumer);return;}}}Set<String> processed = new HashSet<>();for (PropertySourceLoader loader : this.propertySourceLoaders) {for (String fileExtension : loader.getFileExtensions()) {if (processed.add(fileExtension)) {loadForFileExtension(loader, location + name, "." + fileExtension,profile, filterFactory, consumer);}}}}

获取文件内容load方法 并赋值addActiveProfiles、addIncludedProfiles 

		private void load(PropertySourceLoader loader, String location, Profile profile,DocumentFilter filter, DocumentConsumer consumer) {try {Resource resource = this.resourceLoader.getResource(location);if (resource == null || !resource.exists()) {if (this.logger.isTraceEnabled()) {StringBuilder description = getDescription("Skipped missing config ", location, resource, profile);this.logger.trace(description);}return;}if (!StringUtils.hasText(StringUtils.getFilenameExtension(resource.getFilename()))) {if (this.logger.isTraceEnabled()) {StringBuilder description = getDescription("Skipped empty config extension ", location, resource,profile);this.logger.trace(description);}return;}String name = "applicationConfig: [" + location + "]";List<Document> documents = loadDocuments(loader, name, resource);if (CollectionUtils.isEmpty(documents)) {if (this.logger.isTraceEnabled()) {StringBuilder description = getDescription("Skipped unloaded config ", location, resource, profile);this.logger.trace(description);}return;}List<Document> loaded = new ArrayList<>();for (Document document : documents) {if (filter.match(document)) {addActiveProfiles(document.getActiveProfiles());addIncludedProfiles(document.getIncludeProfiles());loaded.add(document);}}Collections.reverse(loaded);if (!loaded.isEmpty()) {loaded.forEach((document) -> consumer.accept(profile, document));if (this.logger.isDebugEnabled()) {StringBuilder description = getDescription("Loaded config file ",location, resource, profile);this.logger.debug(description);}}}catch (Exception ex) {throw new IllegalStateException("Failed to load property "+ "source from location '" + location + "'", ex);}}

 loadDocuments(loader, name, resource);会将文件的属性加载项目中来

7、创建 Banner 打印类

默认打印SpringBootBanner类 看下这个图片是不是很熟悉呢

class SpringBootBanner implements Banner {private static final String[] BANNER = { "","  .   ____          _            __ _ _"," /\\\\ / ___'_ __ _ _(_)_ __  __ _ \\ \\ \\ \\","( ( )\\___ | '_ | '_| | '_ \\/ _` | \\ \\ \\ \\"," \\\\/  ___)| |_)| | | | | || (_| |  ) ) ) )","  '  |____| .__|_| |_|_| |_\\__, | / / / /"," =========|_|==============|___/=/_/_/_/" };

 

8、创建应用上下文

	protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);break;case REACTIVE:contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);break;default:contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);}}catch (ClassNotFoundException ex) {throw new IllegalStateException("Unable create a default ApplicationContext, "+ "please specify an ApplicationContextClass",ex);}}return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);}

容器实际上就是AnnotationConfigServletWebServerApplicationContext类,后面的操作都会基于此类

AnnotationConfigServletWebServerApplicationContext在实例化时还会加载许多类,构造方法

public AnnotationConfigServletWebServerApplicationContext() {this.reader = new AnnotatedBeanDefinitionReader(this);this.scanner = new ClassPathBeanDefinitionScanner(this);}

进行跟进AnnotatedBeanDefinitionReader构造方法,加载

internalConfigurationAnnotationProcessor,internalConfigurationBeanNameGenerator、internalAutowiredAnnotationProcessor等类,这也是为什么类名与实际类名称不同,前面多个internal的原因

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);if (beanFactory != null) {if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);}if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());}}Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));}// Check for JPA support, and if present add the PersistenceAnnotationBeanPostProcessor.if (jpaPresent && !registry.containsBeanDefinition(PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition();try {def.setBeanClass(ClassUtils.forName(PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME,AnnotationConfigUtils.class.getClassLoader()));}catch (ClassNotFoundException ex) {throw new IllegalStateException("Cannot load optional framework class: " + PERSISTENCE_ANNOTATION_PROCESSOR_CLASS_NAME, ex);}def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, PERSISTENCE_ANNOTATION_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_PROCESSOR_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(EventListenerMethodProcessor.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_PROCESSOR_BEAN_NAME));}if (!registry.containsBeanDefinition(EVENT_LISTENER_FACTORY_BEAN_NAME)) {RootBeanDefinition def = new RootBeanDefinition(DefaultEventListenerFactory.class);def.setSource(source);beanDefs.add(registerPostProcessor(registry, def, EVENT_LISTENER_FACTORY_BEAN_NAME));}return beanDefs;}

 

9、准备异常报告器

exceptionReporters  还是一样读取spring.factory文件赋值实例化

org.springframework.boot.SpringBootExceptionReporter=\
org.springframework.boot.diagnostics.FailureAnalyzers

 

这篇关于Spring Boot2 源码 run prepareEnvironment方法 (三)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/868261

相关文章

Conda与Python venv虚拟环境的区别与使用方法详解

《Conda与Pythonvenv虚拟环境的区别与使用方法详解》随着Python社区的成长,虚拟环境的概念和技术也在不断发展,:本文主要介绍Conda与Pythonvenv虚拟环境的区别与使用... 目录前言一、Conda 与 python venv 的核心区别1. Conda 的特点2. Python v

Spring Boot中WebSocket常用使用方法详解

《SpringBoot中WebSocket常用使用方法详解》本文从WebSocket的基础概念出发,详细介绍了SpringBoot集成WebSocket的步骤,并重点讲解了常用的使用方法,包括简单消... 目录一、WebSocket基础概念1.1 什么是WebSocket1.2 WebSocket与HTTP

SpringBoot+Docker+Graylog 如何让错误自动报警

《SpringBoot+Docker+Graylog如何让错误自动报警》SpringBoot默认使用SLF4J与Logback,支持多日志级别和配置方式,可输出到控制台、文件及远程服务器,集成ELK... 目录01 Spring Boot 默认日志框架解析02 Spring Boot 日志级别详解03 Sp

java中反射Reflection的4个作用详解

《java中反射Reflection的4个作用详解》反射Reflection是Java等编程语言中的一个重要特性,它允许程序在运行时进行自我检查和对内部成员(如字段、方法、类等)的操作,本文将详细介绍... 目录作用1、在运行时判断任意一个对象所属的类作用2、在运行时构造任意一个类的对象作用3、在运行时判断

java如何解压zip压缩包

《java如何解压zip压缩包》:本文主要介绍java如何解压zip压缩包问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java解压zip压缩包实例代码结果如下总结java解压zip压缩包坐在旁边的小伙伴问我怎么用 java 将服务器上的压缩文件解压出来,

SpringBoot中SM2公钥加密、私钥解密的实现示例详解

《SpringBoot中SM2公钥加密、私钥解密的实现示例详解》本文介绍了如何在SpringBoot项目中实现SM2公钥加密和私钥解密的功能,通过使用Hutool库和BouncyCastle依赖,简化... 目录一、前言1、加密信息(示例)2、加密结果(示例)二、实现代码1、yml文件配置2、创建SM2工具

Spring WebFlux 与 WebClient 使用指南及最佳实践

《SpringWebFlux与WebClient使用指南及最佳实践》WebClient是SpringWebFlux模块提供的非阻塞、响应式HTTP客户端,基于ProjectReactor实现,... 目录Spring WebFlux 与 WebClient 使用指南1. WebClient 概述2. 核心依

SQL Server配置管理器无法打开的四种解决方法

《SQLServer配置管理器无法打开的四种解决方法》本文总结了SQLServer配置管理器无法打开的四种解决方法,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录方法一:桌面图标进入方法二:运行窗口进入检查版本号对照表php方法三:查找文件路径方法四:检查 S

MyBatis-Plus 中 nested() 与 and() 方法详解(最佳实践场景)

《MyBatis-Plus中nested()与and()方法详解(最佳实践场景)》在MyBatis-Plus的条件构造器中,nested()和and()都是用于构建复杂查询条件的关键方法,但... 目录MyBATis-Plus 中nested()与and()方法详解一、核心区别对比二、方法详解1.and()

Spring Boot @RestControllerAdvice全局异常处理最佳实践

《SpringBoot@RestControllerAdvice全局异常处理最佳实践》本文详解SpringBoot中通过@RestControllerAdvice实现全局异常处理,强调代码复用、统... 目录前言一、为什么要使用全局异常处理?二、核心注解解析1. @RestControllerAdvice2