Spring Boot源码分析之SpringApplication.run

public ConfigurableApplicationContext run(String... args) {
	StopWatch stopWatch = new StopWatch();
	stopWatch.start();
	ConfigurableApplicationContext context = null;
	Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
	configureHeadlessProperty();
	// 通过SPI机制获取spring.factories文件中配置的SpringApplicationRunListener类型实例并进行包装
	// 通常只有一个实现类 org.springframework.boot.context.event.EventPublishingRunListener
	SpringApplicationRunListeners listeners = getRunListeners(args);
	// 通过监听器进行事件发布 此处EventPublishingRunListener利用代理类SimpleApplicationEventMulticaster进行事件发布,事件类型为ApplicationStartingEvent
	// 事件发布之后,此时会触发RestartApplicationListener进行事件的监听操作,创建一个org.springframework.boot.devtools.restart.Restarter对象
	listeners.starting();
	try {
		// 解析从main方法中传入的args
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		// 准备环境,获取或创建,根据在构造SpringApplication时解析的WebApplicationType类型来判断
		// SERVLET->StandardServletEnvironment
		// REACTIVE->StandardReactiveWebEnvironment
		// 其他->StandardEnvironment
		// 其中最主要的作用的是获取系统属性和环境属性,并且会读取系统配置文件并将属性填到environment中了
		// 各种资源的绑定等等
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
		configureIgnoreBeanInfo(environment);
		// 进行Banner的打印 主要是通过SpringApplicationBannerPrinter类进行Banner的打印
		Banner printedBanner = printBanner(environment);
		// 根据WebApplicationType类型创建上下文对象
		// SERVLET -> AnnotationConfigServletWebServerApplicationContext
		// REACTIVE -> AnnotationConfigReactiveWebServerApplicationContext
		// 其他 -> AnnotationConfigApplicationContext
		context = createApplicationContext();
		// 根据SPI机制获取SpringBootExceptionReporter类对象
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[] { ConfigurableApplicationContext.class }, context);
		// 准备上下文
		// 1. 设置环境 environment 到上下文中
		// 2. 处理上下文 比如处理beanNameGenerator resourceLoader conversionService
		// 3. 通过ApplicationContextInitializer来初始化上下文
		// 4. 发布contextPrepared事件
		// 5. 注册单例Bean springApplicationArguments
		// 6. 进行上下文加载 此时只加载了一个主类
		// 7. 发布contextLoaded事件		
		prepareContext(context, environment, listeners, applicationArguments, printedBanner);
		// 刷新上下文 Spring核心逻辑
		refreshContext(context);
		afterRefresh(context, applicationArguments);
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		listeners.started(context);
		callRunners(context, applicationArguments);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		listeners.running(context);
	}
	catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

应用程序事件与监听

ApplicationStartingEvent事件与监听
针对org.springframework.boot.devtools.restart.Restarter类的说明:

Spring Boot提供自动重启的功能,当当前classpath目录下有文件更改时,会自动进行重启。但是并不是所有的文件都会被更改,比如引用的第三方jar包就不会被更改。因此在此处将url路径分为两部分,用两个不同的类加载器来加载,这样在有文件被更改时,不需要去重新加载那些根本不会被修改的第三方jar包。
具体参照官方文档说明:https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/using-spring-boot.html#using-boot-devtools的Automatic Restart章节

Allows a running application to be restarted with an updated classpath. The restarter works by creating a new application ClassLoader that is split into two parts. The top part contains static URLs that don’t change (for example 3rd party libraries and Spring Boot itself) and the bottom part contains URLs where classes and resources might be updated.
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

触发监听器

在这里插入图片描述

二:环境准备

加载环境属性并添加到属性配置列表中

其中主要的系统属性和系统环境属性获取方法其实很简单:

return (Map) System.getProperties();
return (Map) System.getenv();

在这里插入图片描述
在这里插入图片描述

配置转换服务类

这个转换服务类主要用于各种类型数据之间的相互转换,比如将从配置文件中读取的String类型数据转换为对象中需要的各种引用类型,Spring已经提供了各种常用的转换器,当然也可以自己进行自定义
具体可以参考官方文档:https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/spring-boot-features.html#boot-features-external-config-conversion
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

// org.springframework.boot.SpringApplication
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
	// 添加上面的转换服务类
	if (this.addConversionService) {
		ConversionService conversionService = ApplicationConversionService.getSharedInstance();
		environment.setConversionService((ConfigurableConversionService) conversionService);
	}
	// 配置通过控制台传入的参数到environment中
	configurePropertySources(environment, args);
	// 设置当前的激活的profiles版本到environment中
	configureProfiles(environment, args);
}
环境准备事件

此时会发布一个ApplicationEnvironmentPreparedEvent事件,仍然通过与上面相同的ApplicationListener类型的监听器进行处理
在这里插入图片描述
其中的org.springframework.boot.context.config.ConfigFileApplicationListener,在此类中就会进行默认资源文件比如application.properties文件的读取,当然首先是需要解析出当前环境的激活版本(activeProfile)

// org.springframework.boot.context.config.ConfigFileApplicationListener
private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
	// 通过SPI机制装载EnvironmentPostProcessor类型的后置处理器
	List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
	// 该类本身也实现了EnvironmentPostProcessor接口
	postProcessors.add(this);
	// 进行后置处理器的排序
	AnnotationAwareOrderComparator.sort(postProcessors);
	// 进行后置处理器的后置处理
	for (EnvironmentPostProcessor postProcessor : postProcessors) {
		postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
	}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
用户可以自定义EnvironmentPostProcessor类型的后置处理器用于处理环境配置,比如参数加密和解密
具体参考官方文档:https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/spring-boot-features.html#boot-features-application-events-and-listeners
在这里插入图片描述

通过ApplicationContextInitializer处理上下文
public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {
	/**
	 * Initialize the given application context.
	 * @param applicationContext the application to configure
	 */
	void initialize(C applicationContext);
}

Callback interface for initializing a Spring ConfigurableApplicationContext prior to being refreshed.
Typically used within web applications that require some programmatic initialization of the application context. For example, registering property sources or activating profiles against the context’s environment. See ContextLoader and FrameworkServlet support for declaring a “contextInitializerClasses” context-param and init-param, respectively.
ApplicationContextInitializer processors are encouraged to detect whether Spring’s Ordered interface has been implemented or if the @Order annotation is present and to sort instances accordingly if so prior to invocation.

// org.springframework.boot.SpringApplication
// Apply any ApplicationContextInitializers to the context before it is refreshed.
protected void applyInitializers(ConfigurableApplicationContext context) {
	for (ApplicationContextInitializer initializer : getInitializers()) {
		// 依赖于ConfigurableApplicationContext,此处获取泛型类型
		Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
				ApplicationContextInitializer.class);
		Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
		// 进行上下文初始化操作
		initializer.initialize(context);
	}
}

官方相关说明:https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/spring-boot-features.html#boot-features-configfileapplicationcontextinitializer-test-utility

https://docs.spring.io/spring-boot/docs/2.2.5.RELEASE/reference/html/howto.html#howto-customize-the-environment-or-application-context
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

上下文加载
// 当前类:org.springframework.boot.SpringApplication
// Load beans into the application context.
protected void load(ApplicationContext context, Object[] sources) {
	if (logger.isDebugEnabled()) {
		logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
	}
	// 使用BeanDefinitionLoader 来进行加载上下Bean定义 里面包装了用于xml或注解类型的Reader
	BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
	if (this.beanNameGenerator != null) {
		loader.setBeanNameGenerator(this.beanNameGenerator);
	}
	if (this.resourceLoader != null) {
		loader.setResourceLoader(this.resourceLoader);
	}
	if (this.environment != null) {
		loader.setEnvironment(this.environment);
	}
	loader.load();
}

在这里插入图片描述

/**
 * Factory method used to create the {@link BeanDefinitionLoader}.
 * @param registry the bean definition registry
 * @param sources the sources to load
 * @return the {@link BeanDefinitionLoader} that will be used to load beans
 */
protected BeanDefinitionLoader createBeanDefinitionLoader(BeanDefinitionRegistry registry, Object[] sources) {
	// 使用的Bean加载器
	return new BeanDefinitionLoader(registry, sources);
}

在这里插入图片描述
在这里插入图片描述

// org.springframework.context.annotation.AnnotatedBeanDefinitionReader
// Register a bean from the given bean class, deriving its metadata from class-declared annotations.
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
		@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
	// condition条件判断
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

	abd.setInstanceSupplier(instanceSupplier);
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	abd.setScope(scopeMetadata.getScopeName());
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			}
			else if (Lazy.class == qualifier) {
				abd.setLazyInit(true);
			}
			else {
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}
	for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
		customizer.customize(abd);
	}

	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	// 是否生成代理对象
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
	// 进行Bean定义的注册
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

refreshContext(context)调用之前Bean定义情况,此时已经读取了系统默认配置文件的各种属性,定义好了上下文用于读取xml或注解的Reader类等
在这里插入图片描述
在这里插入图片描述

总结:通过以上的逻辑,Spring Boot准备好了上下文环境,接下来会进入上下文刷新阶段,属于Spring的核心逻辑。

发布了34 篇原创文章 · 获赞 1 · 访问量 1533

猜你喜欢

转载自blog.csdn.net/m0_37607945/article/details/104951080