当前位置: 首页 > article >正文

SpringBoot系列 启动流程

文章目录

  • SpringApplication
    • SpringApplication#run
  • 启动流程
    • BootstrapContext
    • SpringApplicationRunListeners
    • prepareEnvironment
      • configureEnvironment
        • configurePropertySources
        • configureProfiles
    • 上下文初始化
      • prepareContext
      • refreshContext
        • prepareRefresh
        • obtainFreshBeanFactory
        • prepareBeanFactory
        • postProcessBeanFactory
        • invokeBeanFactoryPostProcessors
        • registerBeanPostProcessors
        • initMessageSource
        • initApplicationEventMulticaster
        • onRefresh
        • registerListeners
        • finishBeanFactoryInitialization
        • finishRefresh
        • destroyBeans
        • cancelRefresh
    • afterRefresh
    • callRunners
  • Aware 接口


以下面的启动类为例:

@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }
}

下面逐步分析SpringBoot的启动流程

SpringApplication

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
	this.resourceLoader = resourceLoader;
	Assert.notNull(primarySources, "PrimarySources must not be null");
	this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
	this.webApplicationType = WebApplicationType.deduceFromClasspath();
	this.bootstrapRegistryInitializers = new ArrayList<>(
			getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
	setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
	setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
	this.mainApplicationClass = deduceMainApplicationClass();
}

SpringApplication#run

SpringApplication#run(java.lang.String…)方法包含了全部SpringBoot应用启动的流程,启动完毕之后会返回最终的应用上下文ConfigurableApplicationContext,通过这个上下文我们可以获取Spring中的所有配置,Bean信息等

public ConfigurableApplicationContext run(String... args) {
	long startTime = System.nanoTime();
	// 创建 BootstrapContext
	DefaultBootstrapContext bootstrapContext = createBootstrapContext();
	ConfigurableApplicationContext context = null;
	configureHeadlessProperty();
	// 加载spring.factories文件中的SpringApplicationRunListener实例
	SpringApplicationRunListeners listeners = getRunListeners(args);
	// 执行starting回调
	listeners.starting(bootstrapContext, this.mainApplicationClass);
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
		configureIgnoreBeanInfo(environment);
		// 打印Banner信息
		Banner printedBanner = printBanner(environment);
		// 使用ApplicationContextFactory创建ApplicationContext对象
		context = createApplicationContext();
		// 将配置的ApplicationStartup加到ApplicationContext中
		context.setApplicationStartup(this.applicationStartup);
		// 初始化应用上下文
		prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
		// 刷新应用上下文
		refreshContext(context);
		// 应用上下文刷新完毕之后的回调
		afterRefresh(context, applicationArguments);
		Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
		}
		// ApplicationRunListener的started回调
		listeners.started(context, timeTakenToStartup);
		callRunners(context, applicationArguments);
	} catch (Throwable ex) {
		handleRunFailure(context, ex, listeners);
		throw new IllegalStateException(ex);
	}
	try {
		Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
		listeners.ready(context, timeTakenToReady);
	} catch (Throwable ex) {
		handleRunFailure(context, ex, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

启动流程

BootstrapContext

BootstrapContext是一个在Spring Boot和Spring Cloud中使用的引导上下文,它在应用程序启动期间以及环境后处理过程中扮演着重要角色。以下是BootstrapContext的主要作用:

  1. 早期启动阶段的作用
    延迟访问高成本单例:在应用程序的早期启动阶段,BootstrapContext提供了对可能创建成本高昂的单例的延迟访问。这意味着,只有在需要时,这些单例才会被创建和初始化,从而优化了启动时间和资源使用。
    共享单例:在ApplicationContext可用之前,BootstrapContext允许共享必要的单例对象。这对于需要在早期阶段就进行配置或初始化的组件特别有用。
  2. 配置加载与优先级
    加载外部配置:BootstrapContext负责加载外部资源的配置属性,并解释本地外部配置文件(如bootstrap.yml或bootstrap.properties)中的属性。这些配置属性通常用于设置应用程序的基础设施,如服务发现、配置中心等。
    配置优先级:默认情况下,bootstrap属性具有高优先级,并且无法被本地配置覆盖。这确保了基础设施相关的配置不会被意外地覆盖或修改。
  3. 应用程序上下文层级
    作为Parent Context:在Spring Cloud中,BootstrapContext通常作为主应用程序上下文(main ApplicationContext)的父上下文。这意味着主上下文可以继承BootstrapContext中的属性和配置资源。
    属性资源继承:主应用程序上下文可以从BootstrapContext中继承额外的属性资源和配置文件,从而简化了配置管理。
  4. 自定义与扩展
    自定义配置:通过配置/META-INF/spring.factories文件中的org.springframework.cloud.bootstrap.BootstrapConfiguration值,可以自定义BootstrapContext的行为和配置。这为开发人员提供了极大的灵活性和控制力。
    添加属性资源:可以通过向BootstrapContext中添加PropertySourceLocator类型的bean来添加额外的属性资源。这允许开发人员从自定义的来源加载配置属性。
  5. 生命周期管理
    监听启动事件:开发人员可以通过实现ApplicationListener接口来监听BootstrapContext的启动事件,从而执行自定义的初始化操作或配置任务。
    关闭监听:在应用程序上下文关闭时,BootstrapContext也提供了相应的机制来执行清理操作或释放资源。

综上所述,BootstrapContext在Spring Boot和Spring Cloud应用程序中起到了至关重要的作用,它优化了启动过程、管理了配置优先级、支持了应用程序上下文的层级结构、提供了自定义和扩展的能力,并管理了生命周期事件。

private DefaultBootstrapContext createBootstrapContext() {
	DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
	// List<BootstrapRegistryInitializer> bootstrapRegistryInitializers
	this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
	return bootstrapContext;
}

这个bootstrapRegistryInitializers就是在SpringApplication的构造方法里进行加载的
在这里插入图片描述

SpringApplicationRunListeners

SpringApplicationRunListeners负责在Spring Boot应用程序启动的不同阶段广播消息,并传递给实现了ApplicationListener接口的监听器类,以执行自定义逻辑。

SpringApplicationRunListener是一个监听SpringApplication中run方法的接口,它在项目启动过程的各个阶段进行事件的发布。通过实现这个接口,开发者可以在应用程序启动的不同生命周期阶段插入自定义的逻辑。

SpringApplicationRunListeners类内部维护了一个SpringApplicationRunListener的集合,提供了与SpringApplicationRunListener接口一致的方法,方便统一遍历调用所有SpringApplicationRunListener。
实例化:
SpringApplicationRunListeners的实例化发生在SpringApplication的run方法中。它通过调用getRunListeners方法,读取META-INF/spring.factories文件,获取SpringApplicationRunListener的子类(如EventPublishingRunListener)的Class信息,并通过反射API创建其实例。

生命周期方法
SpringApplicationRunListeners接口定义了多个回调方法,这些方法在Spring Boot应用程序启动的不同阶段被触发:

  1. starting():在Spring Boot应用程序开始启动时触发。此时,可以执行一些自定义的初始化操作。
  2. environmentPrepared(ConfigurableEnvironment environment):在环境准备好后触发。此时,应用程序上下文尚未创建,但环境已经配置好,允许监听器在此阶段对环境进行进一步的自定义配置。
  3. contextPrepared(ConfigurableApplicationContext context):在应用程序上下文准备好后触发。此时,应用程序上下文已经创建并准备好,但尚未加载任何配置。
  4. contextLoaded(ConfigurableApplicationContext context):在应用程序上下文加载完成后触发。此时,应用程序上下文已经被刷新,但尚未启动。
  5. started(ConfigurableApplicationContext context):在应用程序上下文刷新且应用启动时触发。此时,可以在CommandLineRunner和ApplicationRunners唤醒前执行一些自定义操作。
  6. running(ConfigurableApplicationContext context):在应用程序已经启动并准备好后触发。此时,代表程序已经准备好处理请求。
  7. failed(ConfigurableApplicationContext context, Throwable exception):在应用程序启动失败时触发。此时,可以执行一些自定义的失败处理逻辑。

实现与应用
开发者可以通过实现SpringApplicationRunListeners接口,并在META-INF/spring.factories文件中注册自定义的SpringApplicationRunListener实现类,以在应用程序启动的不同阶段插入自定义逻辑。

例如,可以实现一个自定义的SpringApplicationRunListener,在starting()方法中打印一条消息,以指示应用程序已经开始启动。或者,在environmentPrepared()方法中,可以根据环境变量或配置文件中的设置来动态调整应用程序的配置。

注意事项

  1. 顺序性:由于SpringApplicationRunListeners的回调方法是在应用程序启动的不同阶段被触发的,因此它们的执行顺序是固定的。开发者需要确保在正确的阶段执行自定义逻辑。
  2. 异常处理:在实现SpringApplicationRunListeners的回调方法时,需要注意异常处理。如果某个方法抛出异常,可能会导致应用程序启动失败。因此,建议在方法中添加适当的异常处理逻辑。

综上所述,SpringApplicationRunListeners是Spring Boot框架中用于监听应用程序启动过程的重要组件。通过实现和注册自定义的SpringApplicationRunListener实现类,开发者可以在应用程序启动的不同阶段插入自定义逻辑,从而实现更灵活的应用程序配置和管理。

prepareEnvironment

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
		DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
	// 创建ConfigurableEnvironment
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	// 配置ConfigurableEnvironment
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	// 调用SpringApplicationRunListener的environmentPrepared回调
	listeners.environmentPrepared(bootstrapContext, environment);
	DefaultPropertiesPropertySource.moveToEnd(environment);
	Assert.state(!environment.containsProperty("spring.main.environment-prefix"),
			"Environment prefix cannot be set via properties.");
	// 属性绑定
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
		environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}

org.springframework.boot.ApplicationContextFactory是springboot2.4.0新加的一个策略接口,它定义了如何创建 ApplicationContext 实例的工厂方法。

configureEnvironment

protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
	if (this.addConversionService) {
		environment.setConversionService(new ApplicationConversionService());
	}
	configurePropertySources(environment, args);
	configureProfiles(environment, args);
}
configurePropertySources

org.springframework.core.env.PropertySources 是 Spring 框架中用于管理和保存属性配置的关键接口。它是多个 PropertySource 的集合,为应用程序提供了一个统一的配置属性源访问接口。以下是对 PropertySources 的详细解释:

PropertySources 接口扩展了 Iterable<PropertySource<?>>,意味着它可以遍历其中的 PropertySource 元素。每个 PropertySource 都代表了一个配置源,如系统环境变量、命令行参数、属性文件等。PropertySources 通过提供统一的方法来访问这些配置源中的属性。

虽然 PropertySources 本身是一个接口,没有直接定义获取属性的方法,但它通过其内部的 PropertySource 元素来间接提供这些功能。每个 PropertySource 都有一个 getProperty(String name) 方法,用于根据属性名获取属性值。此外,PropertySources 的实现类(如 MutablePropertySources)通常会提供一些方法来添加、删除或修改 PropertySource 元素。

属性源的加载顺序与优先级
在 Spring 应用程序中,PropertySources 中的属性源通常按照特定的顺序加载,并且具有不同的优先级。例如,Spring Boot 在启动时,会通过 PropertySourcesPlaceholderConfigurer 装载 PropertySources,并往其中添加 environmentProperties 和 localProperties 等属性源。这些属性源的加载顺序和优先级决定了当存在多个相同名称的属性时,哪个属性值会被优先使用。

PropertySources 在 Spring 应用程序中广泛应用于配置属性的管理和访问。以下是一些常见的应用场景:

  1. 多配置文件支持:Spring Boot 支持通过 @PropertySource 或 @PropertySources 注解来加载多个配置文件,这些配置文件会被添加到 PropertySources 中。
  2. 系统环境变量与命令行参数:Spring 允许将系统环境变量和命令行参数作为属性源添加到 PropertySources 中,从而方便地在不同环境下配置应用程序。
  3. 自定义属性源:开发者可以通过实现 PropertySource 接口来创建自定义的属性源,并将其添加到 PropertySources 中,以满足特定的配置需求。

五、注意事项

  1. 属性名的唯一性:在 PropertySources 中,每个属性名应该是唯一的。如果存在多个相同名称的属性,那么优先级较高的属性源中的属性值将被优先使用。
  2. 属性值的类型转换:在获取属性值时,可能需要进行类型转换。Spring 提供了丰富的类型转换机制来支持这一需求。
  3. 安全性:在处理敏感配置信息时,需要注意保护这些信息的安全性,避免泄露给未经授权的用户或系统。

综上所述,org.springframework.core.env.PropertySources 是 Spring 框架中用于管理和保存属性配置的重要接口。通过理解和使用它,开发者可以更加灵活地配置和管理 Spring 应用程序中的属性信息。

protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
	// 所有配置属性
	MutablePropertySources sources = environment.getPropertySources();
	// 添加默认属性
	if (!CollectionUtils.isEmpty(this.defaultProperties)) {  // 1
		// 添加到末尾
		DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
	}
	// 命令行的配置属性处理,即是否添加main方法的参数
	if (this.addCommandLineProperties && args.length > 0) {
		String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
		if (sources.contains(name)) {
			PropertySource<?> source = sources.get(name);
			CompositePropertySource composite = new CompositePropertySource(name);
			composite.addPropertySource(new SimpleCommandLinePropertySource("springApplicationCommandLineArgs", args));
			composite.addPropertySource(source);
			sources.replace(name, composite);
		} else {
			// 添加到末尾
			sources.addFirst(new SimpleCommandLinePropertySource(args));
		}
	}
}
  1. 可以通过SpringApplication#setDefaultProperties()进行设置
configureProfiles

上下文初始化

prepareContext

用于ApplicationContext的初始化操作,加载上下文的组件,执行一些生命周期回调等等

private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
		ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
		ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	// 设置ApplicationContext的相关组件
	postProcessApplicationContext(context);
	// 执行ApplicationContextInitializer#initialize回调
	applyInitializers(context);
	// context准备完毕: 执行SpringApplicationRunListener#contextPrepared回调
	listeners.contextPrepared(context);
	bootstrapContext.close(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
		((AbstractAutowireCapableBeanFactory) beanFactory).setAllowCircularReferences(this.allowCircularReferences);
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// 添加PropertySourceOrderingBeanFactoryPostProcessor这个BeanFactoryPostProcessor
	context.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));
	// Load the sources
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	// 加载SpringApplication的sources对象数组的Bean信息
	load(context, sources.toArray(new Object[0]));
	// context加载完毕: 执行SpringApplicationRunListener#contextLoaded回调
	listeners.contextLoaded(context);
}

refreshContext

加载或刷新配置的持久化,这些配置可以来自 XML 文件、properties 文件、关心数据库等等。因为该方法是一个启动方法,如果失败了,它应该销毁已经创建的单例,以避免出现悬挂资源(dangling resources),换句话说,要么实例化所有的单例,要么一个也不实例化。

void refresh() throws BeansException, IllegalStateException;

AbstractApplicationContext 是 ApplicationContext 的一个抽象实现类。和普通的 BeanFactory 不同的是,ApplicationContext 可以检测到它的内部 BeanFactory 中定义的特殊 Bean:自动完成 BeanFactoryPostProcessor、BeanPostProcessor、ApplicationListener 的注册。

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);
			beanPostProcess.end();

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		} catch (BeansException ex) {

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();
			// Reset 'active' flag.
			cancelRefresh(ex);
			// Propagate exception to caller.
			throw ex;
		} finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
			contextRefresh.end();
		}
	}
}
prepareRefresh

这里是做一些准备工作,包括设置开始时间、active 状态、PropertySources 的初始化等等

protected void prepareRefresh() {
	// Switch to active.
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	this.active.set(true);

	// ...

	// Initialize any placeholder property sources in the context environment.
	initPropertySources();

	// Validate that all properties marked as required are resolvable:
	// see ConfigurablePropertyResolver#setRequiredProperties
	getEnvironment().validateRequiredProperties();

	// Store pre-refresh ApplicationListeners...
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
	} else {
		// Reset local application listeners to pre-refresh state.
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}

	// Allow for the collection of early ApplicationEvents,
	// to be published once the multicaster is available...
	this.earlyApplicationEvents = new LinkedHashSet<>();
}
obtainFreshBeanFactory

告诉当前ApplicationContext的子类刷新内部的 BeanFactory,然后返回刷新后的 BeanFactory

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	refreshBeanFactory();
	return getBeanFactory();
}

refreshBeanFactory是
org.springframework.context.support.AbstractApplicationContext的一个抽象方法,需要子类实现,直接的子类有2个,而refreshBeanFactory方法在两个里面都有实现
在这里插入图片描述
一般来说基于WEB的系统的ApplicationContext的类型是org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext,而它是AbstractRefreshableApplicationContext这个分支下的,所以我们先看它

@Override
protected final void refreshBeanFactory() throws BeansException {
	if (hasBeanFactory()) {
		destroyBeans();
		closeBeanFactory();
	}
	try {
		// 创建BeanFactory
		DefaultListableBeanFactory beanFactory = createBeanFactory();
		beanFactory.setSerializationId(getId());
		customizeBeanFactory(beanFactory);
		// 加载所有Bean定义信息,这里会根据不同的配置类型进行加载
		loadBeanDefinitions(beanFactory);
		this.beanFactory = beanFactory;
	} catch (IOException ex) {
		throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
	}
}

loadBeanDefinitions将bean定义加载到给定的BeanFactory中,通常是通过委托给一个或多个BeanDefinitionReader完成的。
在这里插入图片描述
BeanDefinitionReader的继承体系如下:分别对应BeanDefinition存放的不同位置
在这里插入图片描述

prepareBeanFactory

配置 BeanFactory ,例如设置 context 的 class loader 和 post processor

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Tell the internal bean factory to use the context's class loader etc.
	beanFactory.setBeanClassLoader(getClassLoader());
	if (!shouldIgnoreSpel) {
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	}
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);

	// BeanFactory interface not registered as resolvable type in a plain factory.
	// MessageSource registered (and found for autowiring) as a bean.
	beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
	beanFactory.registerResolvableDependency(ResourceLoader.class, this);
	beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
	beanFactory.registerResolvableDependency(ApplicationContext.class, this);

	// Register early post-processor for detecting inner beans as ApplicationListeners.
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// Register default environment beans.
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
	if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
		beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
	}
}
postProcessBeanFactory

对 BeanFactory 进行后处理,默认的实现为空,交给子类去扩展。可以对 beanFactory 进行想要的操作。比如 GenericWebApplicationContext 的实现如下:

@Override
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	if (this.servletContext != null) {
		beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext));
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
	}
	WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
	WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext);
}
invokeBeanFactoryPostProcessors

调用 BeanFactoryPostProcessor

registerBeanPostProcessors

实例化并且调用所有已注册的 BeanPostProcessor

initMessageSource

org.springframework.context.MessageSource是Spring框架中用于解析消息的顶层接口,它支持参数化和国际化信息。

MessageSource接口的主要功能是从资源文件中检索和解析消息。这些资源文件通常包含键值对,其中键是消息的标识符,值是实际要显示的字符串。通过MessageSource,开发者可以在代码中通过键来获取对应的消息值,从而实现了消息与代码的分离,提高了代码的可读性和可维护性。

MessageSource接口提供了多个重载的getMessage方法,用于获取消息。以下是几个常用的方法:

  1. String getMessage(String code, Object[] args, String defaultMessage, Locale locale):根据指定的消息代码(code)、参数数组(args)、默认消息(defaultMessage)和语言环境(locale)来获取消息。如果找不到指定语言环境的消息,则使用默认消息。
  2. String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException:与上一个方法类似,但无法指定默认消息。如果找不到消息,会抛出NoSuchMessageException异常。
  3. String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException:使用MessageSourceResolvable对象来封装消息代码、参数和默认消息,然后根据指定的语言环境来获取消息。如果找不到消息,也会抛出NoSuchMessageException异常。
initApplicationEventMulticaster

初始化上下文中的事件机制

onRefresh

留给子类去实现,用于初始化其他特殊的 bean。比如 Spring Boot 中ServletWebServerApplicationContext 就是在这一步去创建的 web server

registerListeners
protected void registerListeners() {
	// Register statically specified listeners first.
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}

	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	for (String listenerBeanName : listenerBeanNames) {
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}

	// Publish early application events now that we finally have a multicaster...
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (!CollectionUtils.isEmpty(earlyEventsToProcess)) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}
finishBeanFactoryInitialization

完成当前 context 的 beanFactory 的初始化,初始化剩下所有的不是懒加载的单例Bean对象

Bean的初始化都是通过BeanFactory#getBean进行的,也就是常说的将一个类型注册单例对象到容器并进行初始化

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize conversion service for this context.
	// CONVERSION_SERVICE_BEAN_NAME => conversionService
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// Register a default embedded value resolver if no BeanFactoryPostProcessor
	// (such as a PropertySourcesPlaceholderConfigurer bean) registered any before:
	// at this point, primarily for resolution in annotation attribute values.
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	beanFactory.freezeConfiguration();

	// Instantiate all remaining (non-lazy-init) singletons.
	// 项目中自定义的所有Bean就是在此时进行实例化
	beanFactory.preInstantiateSingletons();
}

ConfigurableListableBeanFactory定义的方法,在DefaultListableBeanFactory中实现:org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

@Override
public void preInstantiateSingletons() throws BeansException {
	// ...

	// Iterate over a copy to allow for init methods which in turn register new bean definitions.
	// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
	List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

	// Trigger initialization of all non-lazy singleton beans...
	for (String beanName : beanNames) {
		// 先获取BeanDefinition信息
		RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
		// 不是抽象类,并且是单例,且非懒加载
		if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			// 判断是否FactoryBean实例
			if (isFactoryBean(beanName)) {
				Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
				if (bean instanceof FactoryBean) {
					FactoryBean<?> factory = (FactoryBean<?>) bean;
					boolean isEagerInit;
					if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
						isEagerInit = AccessController.doPrivileged(
								(PrivilegedAction<Boolean>) ((SmartFactoryBean<?>) factory)::isEagerInit,
								getAccessControlContext());
					} else {
						isEagerInit = (factory instanceof SmartFactoryBean &&
								((SmartFactoryBean<?>) factory).isEagerInit());
					}
					if (isEagerInit) {
						getBean(beanName);
					}
				}
			} else {
				getBean(beanName);
			}
		}
	}

	// Trigger post-initialization callback for all applicable beans...
	for (String beanName : beanNames) {
		Object singletonInstance = getSingleton(beanName);
		if (singletonInstance instanceof SmartInitializingSingleton) {
			StartupStep smartInitialize = getApplicationStartup().start("spring.beans.smart-initialize")
					.tag("beanName", beanName);
			SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
			if (System.getSecurityManager() != null) {
				AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
					smartSingleton.afterSingletonsInstantiated();
					return null;
				}, getAccessControlContext());
			} else {
				smartSingleton.afterSingletonsInstantiated();
			}
			smartInitialize.end();
		}
	}
}

如果是SmartFactoryBean,则会根据一些条件判断是否要立即进行初始化,SmartFactoryBean#isEagerInit方法

如果是普通的FactoryBean,只有FactoryBean这个工厂Bean对象会被 Spring 容器初始化了,我们的FactoryBean对应的那个对象其实还没被初始化,要在第一次使用的时候,才会被初始化。

finishRefresh

完成当前 context 的 refresh 操作,调用 LifecycleProcessor 的 onRefresh 方法,发布 ContextRefreshedEvent 事件

protected void finishRefresh() {
	// Clear context-level resource caches (such as ASM metadata from scanning).
	clearResourceCaches();

	// Initialize lifecycle processor for this context.
	initLifecycleProcessor();

	// Propagate refresh to lifecycle processor first.
	getLifecycleProcessor().onRefresh();

	// Publish the final event.
	publishEvent(new ContextRefreshedEvent(this));

	// Participate in LiveBeansView MBean, if active.
	if (!NativeDetector.inNativeImage()) {
		LiveBeansView.registerApplicationContext(this);
	}
}
destroyBeans

内部调用的是
org.springframework.beans.factory.config.ConfigurableBeanFactory#destroySingletons,用于出错时清除所有的单例对象

@Override
public void destroySingletons() {
	super.destroySingletons();
	updateManualSingletonNames(Set::clear, set -> !set.isEmpty());
	clearByTypeCache();
}

// DefaultSingletonBeanRegistry
public void destroySingletons() {
	synchronized (this.singletonObjects) {
		this.singletonsCurrentlyInDestruction = true;
	}

	String[] disposableBeanNames;
	synchronized (this.disposableBeans) {
		disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet());
	}
	for (int i = disposableBeanNames.length - 1; i >= 0; i--) {
		destroySingleton(disposableBeanNames[i]);
	}

	this.containedBeanMap.clear();
	this.dependentBeanMap.clear();
	this.dependenciesForBeanMap.clear();

	clearSingletonCache();
}

// 清除三级缓存
protected void clearSingletonCache() {
	synchronized (this.singletonObjects) {
		this.singletonObjects.clear();
		this.singletonFactories.clear();
		this.earlySingletonObjects.clear();
		this.registeredSingletons.clear();
		this.singletonsCurrentlyInDestruction = false;
	}
}
cancelRefresh

由于出现异常,需要取消上下文刷新操作

afterRefresh

afterRefresh是SpringApplication留给子类继承实现的一个方法,相当于一个回调

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

callRunners

这里会调用另外2个扩展点:ApplicationRunner和CommandLineRunner,此时上下文已经刷新完毕

private void callRunners(ApplicationContext context, ApplicationArguments args) {
	context.getBeanProvider(Runner.class).orderedStream().forEach((runner) -> {
		if (runner instanceof ApplicationRunner) {
			callRunner((ApplicationRunner) runner, args);
		}
		if (runner instanceof CommandLineRunner) {
			callRunner((CommandLineRunner) runner, args);
		}
	});
}

Aware 接口

Aware 接口由 org.springframework.context.support.ApplicationContextAwareProcessor 进行处理

  • BeanNameAware: org.springframework.beans.factory.BeanNameAware
  • BeanFactoryAware: org.springframework.beans.factory.BeanFactoryAware
  • ApplicationContextAware: org.springframework.context.ApplicationContextAware
  • MessageSourceAware: org.springframework.context.MessageSourceAware
  • ResourceLoaderAware: org.springframework.context.ResourceLoaderAware
@Override
@Nullable
public Object postProcessBeforeInitialization(Object bean, 
			String beanName) throws BeansException {
	if (!(bean instanceof EnvironmentAware 
			|| bean instanceof EmbeddedValueResolverAware 
			|| bean instanceof ResourceLoaderAware 
			|| bean instanceof ApplicationEventPublisherAware
			|| bean instanceof MessageSourceAware 
			|| bean instanceof ApplicationContextAware 
			|| bean instanceof ApplicationStartupAware)) {
		return bean;
	}

	AccessControlContext acc = null;
	if (System.getSecurityManager() != null) {
		acc = this.applicationContext.getBeanFactory()
				.getAccessControlContext();
	}

	if (acc != null) {
		AccessController.doPrivileged((PrivilegedAction<Object>) 
			() -> { invokeAwareInterfaces(bean);
				return null;
			}, acc);
	} else {
		// 执行 Aware 接口
		invokeAwareInterfaces(bean);
	}
	return bean;
}

private void invokeAwareInterfaces(Object bean) {
	if (bean instanceof EnvironmentAware) {
		((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());
	}
	if (bean instanceof EmbeddedValueResolverAware) {
		((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);
	}
	if (bean instanceof ResourceLoaderAware) {
		((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);
	}
	if (bean instanceof ApplicationEventPublisherAware) {
		((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);
	}
	if (bean instanceof MessageSourceAware) {
		((MessageSourceAware) bean).setMessageSource(this.applicationContext);
	}
	if (bean instanceof ApplicationStartupAware) {
		((ApplicationStartupAware) bean).setApplicationStartup(this.applicationContext.getApplicationStartup());
	}
	if (bean instanceof ApplicationContextAware) {
		((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
	}
}

http://www.kler.cn/news/341516.html

相关文章:

  • fastreport导出PDF后style bold粗体斜体等字体风格不显示的原因
  • LeetCode 54 Spiral Matrix 解题思路和python代码
  • mybatisPlus对于pgSQL中UUID和UUID[]类型的交互
  • 构建高效数据处理桥梁:探索基于数据库驱动的自定义TypeHandler解决方案
  • 基于esp8266的nodemcu实现网页配置wifi功能
  • SpringBoot框架在服装生产管理中的创新应用
  • ANSYS Workbench随机连通孔结构建模
  • 【Cursor教程】探索Cursor颠覆编程体验的创新工具!教程+示例+快捷键
  • Github 2024-10-03Go开源项目日报Top10
  • LeetCode讲解篇之34. 在排序数组中查找元素的第一个和最后一个位置
  • zigbee学习
  • C++-容器适配器- stack、queue、priority_queue和仿函数
  • 重生之我们在ES顶端相遇第 20 章 - Mapping 参数设置大全(进阶)
  • 交叉编译(移植)
  • 深入解析MySQL事务管理:ACID特性与基本操作
  • 文件夹作为普通文件而非子模块管理
  • Unity实现自定义图集(三)
  • 【操作系统】引导(Boot)电脑的奇妙开机过程
  • LeetCode hot100---栈专题(C++语言)
  • Stable Diffusion绘画 | 如何做到不同动作表情,人物角色保持一致性(上篇)