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


以下面的启动类为例:

@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();// 创建 BootstrapContextDefaultBootstrapContext 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> bootstrapRegistryInitializersthis.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) {// 创建ConfigurableEnvironmentConfigurableEnvironment environment = getOrCreateEnvironment();// 配置ConfigurableEnvironmentconfigureEnvironment(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 beansConfigurableListableBeanFactory 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这个BeanFactoryPostProcessorcontext.addBeanFactoryPostProcessor(new PropertySourceOrderingBeanFactoryPostProcessor(context));// Load the sourcesSet<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#setRequiredPropertiesgetEnvironment().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 {// 创建BeanFactoryDefaultListableBeanFactory 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 => conversionServiceif (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);}});
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/441213.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MISC - 第13天(python脚本 重命名文件,拼接二维码,cloacked-pixel工具,中文电码,五笔编码)

前言 各位师傅大家好&#xff0c;我是qmx_07&#xff0c;今天继续讲解MISC的相关知识 [安洵杯 2019]吹着贝斯扫二维码 附件信息: 使用APCHPR暴力破解工具&#xff0c;flag.zip 破解失败可能线索在其他文件&#xff0c;放到hxd查看 在hxd中&#xff0c;发现该文件头JFIF 是j…

晶体规格书及匹配测试

一、晶体参数介绍 晶体的电气规格相对比较简单,如下: 我们逐一看看每个参数, FL就是晶体的振动频率,这个晶体是24.576MHz的。 CL就是负载电容,决定了晶体频率是否准确,包括外接的实际电容、芯片的等效电容以及PCB走线的寄生电容等,核心参数。 Frequency Tolerance是…

matlab碳交易机制下考虑需求响应的综合能源系统优化运行

目录 1 主要内容 架构模型&#xff1a; 需求响应模型&#xff1a; 目标函数&#xff1a; 对比算例设计&#xff1a; 2 部分程序 3 程序结果 4 下载链接 1 主要内容 该程序复现文献《碳交易机制下考虑需求响应的综合能源系统优化运行》&#xff0c;解决碳交易机制下考虑…

工业缺陷检测深度学习方法

工业缺陷检测深度学习方法 基于深度学习的工业缺陷检测方法可以降低传统人工质检的成本, 提升检测的准确性与效率, 因而在智能制造中扮演重要角色, 并逐渐成为计算机视觉领域新兴的研究热点之一. 其被广泛地应用 于无人质检、智能巡检、质量控制等各种生产与运维场景中. 本综述…

Spring Boot驱动的足球青训俱乐部管理解决方案

1 绪论 1.1研究背景 随着科技的发展&#xff0c;计算机的应用&#xff0c;人们的生活方方面面都和互联网密不可分。计算机的普及使得人们的生活更加方便快捷&#xff0c;网络也遍及到我们生活的每个角落&#xff0c;二十一世纪信息化时代的到来&#xff0c;随着社会科技的不断…

241007深度学习之LeNet

目录 1.LeNet介绍2.组成3.代码实现 1.LeNet介绍 LeNet是最早发布的卷积神经网络之一,他是由AT&T贝尔实验室的研究员Yann LeCun在1989年提出的(并且以其命名),目的是识别图像中手写数字.当时,Yann LeCun发表了第一篇通过反向传播成功训练卷积神经网络的研究论文,这项工作代…

关于CSS Grid布局

关于CSS Grid布局 实际效果参考 参考代码 <template><view class"baseInfo"><up-image class"cover" height"160rpx" width"120rpx" :src"bookInfo.cover"><template #error><view style"…

基于Zynq SDIO WiFi移植二(支持2.4/5G)

1 SDIO设备识别 经过编译&#xff0c;将移植好的uboot、kernel、rootFS、ramdisk等烧录到Flash中&#xff0c;上电启动&#xff0c;在log中&#xff0c;可看到sdio设备 [ 1.747059] mmc1: queuing unknown CIS tuple 0x01 (3 bytes) [ 1.761842] mmc1: queuing unknown…

卫星测绘AI技术-立哥尖端科研

分布式微波干涉测绘卫星是以多颗满足一定编队构形的卫星为平台&#xff0c;以合成孔径雷达 和高精度星间相对状态测量设备等为有效载荷&#xff0c;具备全天时、全天候获取雷达干涉影像数 据&#xff0c;快速测制全球数字表面模型、数字雷达正射影像等测绘产品能力的卫星系统…

点可云ERP进销存V8版本——其他支出单使用说明

其他支出单用于记录除采购内容外其支出资金&#xff0c;如&#xff1a;人工运输费、安装维修服务、差旅报销等。新增保存之后&#xff0c;对应资金账户将减少金额额度&#xff0c;并做存储记录&#xff0c;可在现金银行报表中体现。 新增操作 接下来我们讲解新增单据步骤。如上…

PHP 基础语法详解

PHP 基础语法详解 PHP&#xff08;全称&#xff1a;PHP: Hypertext Preprocessor&#xff09;是一种广泛应用的服务器端脚本语言&#xff0c;特别适用于 Web 开发。它易于学习&#xff0c;且能够快速构建动态网站。本篇博客将详细介绍 PHP 的基础语法&#xff0c;帮助初学者理…

[OS] 编译 Linux 内核

编译 Linux 内核&#xff1a;详细教程与 Kthreads 入门结合 我们将学习如何编译 Linux 内核&#xff0c;同时结合 Kthreads 的知识来理解各个步骤的目的。对于虚拟环境下的开发环境配置&#xff0c;本文将为你提供逐步指导。 1. 下载内核源代码 首先&#xff0c;我们需要从官…

第 1 章 MyBatis快速入门

1.1 ORM简介 ORM&#xff08;Object Relational Mapping&#xff0c;对象——关系映射&#xff09;框架的主要功能是根据映射配置文件&#xff0c;完成数据在对象模型与关系模型之间的映射&#xff0c;同时出屏蔽了连接数据库、创建 Statement 对象、执行 SQL、读取 ResultSet…

(Linux驱动学习 - 8).信号异步通知

一.异步通知简介 1.信号简介 信号类似于我们硬件上使用的“中断”&#xff0c;只不过信号是软件层次上的。算是在软件层次上对中断的一种模拟&#xff0c;驱动可以通过主动向应用程序发送信号的方式来报告自己可以访问了&#xff0c;应用程序获取到信号以后就可以从驱动设备中…

【技术】Jaskson的序列化与反序列化

文章目录 概念解释1.Jasksona.JSONJSON 的基本特点JSON 的基本结构JSON 示例 b.ObjectMapper类 2.序列化与反序列化a.序列化对象序列化集合序列化ListSetMap b.反序列化反序列化单个对象反序列化集合对象 概念解释 1.Jaskson Jackson 是一个用于处理 JSON 数据的 Java 库,所以…

k8s实战-1

k8s实战-1 一、资源创建方式1.命令行2.yaml 二、命名空间三、Pod总结 一、资源创建方式 1.命令行 就是直接通过命令的方式创建&#xff0c;比如我要创建namespace&#xff0c; kubectl create namespace hello删除&#xff1a; kubectl delete -f hello2.yaml 简单来说&am…

用java编写飞机大战

游戏界面使用JFrame和JPanel构建。背景图通过BG类绘制。英雄机和敌机在界面上显示并移动。子弹从英雄机发射并在屏幕上移动。游戏有四种状态&#xff1a;READY、RUNNING、PAUSE、GAMEOVER。状态通过鼠标点击进行切换&#xff1a;点击开始游戏&#xff08;从READY变为RUNNING&am…

无人机单目+激光+IMU复杂弧形(隧道)退化场景SLAM技术详解

无人机在复杂弧形&#xff08;如隧道&#xff09;退化场景中的SLAM&#xff08;同时定位与地图构建&#xff09;技术&#xff0c;结合单目相机、激光雷达&#xff08;LiDAR&#xff09;和惯性测量单元&#xff08;IMU&#xff09;时&#xff0c;能够显著提升定位与建图的准确性…

在忘记密码的情况下重新访问手机?5种忘记密码解锁Android手机的方法

无需密码即可访问Android手机。 即使你忘记了密码&#xff0c;你也可以解锁你的Android手机&#xff0c;但你通常需要将手机恢复出厂设置。 您可以通过执行出厂恢复或使用“查找我的设备”网站解锁大多数Android手机。 如果你不再有密码&#xff0c;这里有五种解锁安卓手机的…

E37.【C语言】动态内存管理练习题

目录 1. 答案速查 分析 源代码分析 反汇编代码分析(底层) 2. 答案速查 分析 3. 答案速查 分析 VS逐步调试 1. 求下列代码的执行结果 #include <stdio.h> char* GetMemory(void) {char p[] "hello world";return p; }void Test(void) {char* str…