上一篇文章分析了除 refresh 方法外的流程,并着重分析了 load 方法,这篇文章就主要分析 refresh 方法,可以说 refresh 方法是 springboot 启动流程最重要的一环,没有之一。

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();
}

该方法是由 AnnotationConfigServletWebServerApplicationContext 类调用的,不过它也是调用的父类的方法,所以你可以直接挪到 AbstractApplicationContext 抽象类即可。

一、invokeBeanFactoryPostProcessors

if (beanFactory instanceof BeanDefinitionRegistry) {
	BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
	List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
	List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
	for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
		if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
			BeanDefinitionRegistryPostProcessor registryProcessor =
					(BeanDefinitionRegistryPostProcessor) postProcessor;
			registryProcessor.postProcessBeanDefinitionRegistry(registry);
			registryProcessors.add(registryProcessor);
		}
		else {
			regularPostProcessors.add(postProcessor);
		}
	}
	......
}

这里的 beanFactory 是 DefaultListableBeanFactory,它是 BeanDefinitionRegistry 是实例,至于怎么来的我想你应该清楚哈。然后在这片段代码里,我们比较注意的是 registryProcessor.postProcessBeanDefinitionRegistry(registry)。
这时你应该想到 beanFactoryPostProcessors 的值是怎么来的,如果你往前追溯的话,可以知道是在 prepareContext 方法里赋值的。这里我们选其中一个 SharedMetadataReaderFactoryContextInitializer 看看:
它会注册 SharedMetadataReaderFactoryBean 工厂并且会额外注册一个 processor,这也是后面为啥会多次遍历的原因。
另外需要注意到的是它分成了两个类型的 processor,一个是 regularPostProcessors,另一个是 registryProcessors。

// Do not initialize FactoryBeans here: We need to leave all regular beans
// uninitialized to let the bean factory post-processors apply to them!
// Separate between BeanDefinitionRegistryPostProcessors that implement
// PriorityOrdered, Ordered, and the rest.
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
String[] postProcessorNames =
		beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
	if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
		currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
		processedBeans.add(ppName);
	}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();

接着我们看这段代码,这里的注释意思很清楚:不要在这里实例化 FactoryBeans,我们需要把所有的 regular beans 留给 beanFactory 的 post-processors 去处理。然后将 BeanDefinitionRegistryPostProcessors 分离为实现了 PriorityOrdered、Ordered 两类,以及剩下的为一类,然后调用 invokeBeanDefinitionRegistryPostProcessors 方法进行处理。

private static void invokeBeanDefinitionRegistryPostProcessors(
		Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry, ApplicationStartup applicationStartup) {
	for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
		StartupStep postProcessBeanDefRegistry = applicationStartup.start("spring.context.beandef-registry.post-process")
				.tag("postProcessor", postProcessor::toString);
		postProcessor.postProcessBeanDefinitionRegistry(registry);
		postProcessBeanDefRegistry.end();
	}

我们以其中一个 postProcessor 进行说明,比如 ConfigurationClassPostProcessor:
它的作用是在应用程序上下文启动时,扫描配置类(被 @Configuration 注解标记的类)并解析其中的 @Bean 注解,将其转化为对应的BeanDefinition对象,并注册到BeanDefinitionRegistry 中。这样,这些配置类中的 @Bean 方法就可以被容器识别并实例化为相应的 Bean 对象。
接着就开始调用 invokeBeanFactoryPostProcessors 来处理 regularPostProcessors 和 registryProcessors,

private static void invokeBeanFactoryPostProcessors(
		Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
	for (BeanFactoryPostProcessor postProcessor : postProcessors) {
		StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
				.tag("postProcessor", postProcessor::toString);
		postProcessor.postProcessBeanFactory(beanFactory);
		postProcessBeanFactory.end();
	}
}

它会调用这些工厂的 postProcessBeanFactory 方法,还是拿 ConfigurationClassPostProcessor 举例:
它的作用是对 BeanFactory 进行进一步的处理和配置,确保配置类中的 Bean 能够正确注册到容器中,并处理配置类之间的依赖关系和导入关系。

二、registerBeanPostProcessors

该方法和上面的步骤也差不多,registerBeanPostProcessors 方法的作用是将所有的 BeanPostProcessor(后置处理器)注册到 BeanFactory 中。在应用程序上下文启动时,会调用该方法来注册所有的 BeanPostProcessor,以便在 Bean 的创建过程中进行相应的处理。BeanPostProcessor 是 Spring 框架提供的一种机制,用于在Bean的实例化和初始化过程中对 Bean 进行额外的处理。它可以在 Bean 实例化之前和初始化之后对 Bean 进行修改、增强或进行其他操作。通常,开发人员可以通过实现 BeanPostProcessor 接口来自定义自己的后置处理器。registerBeanPostProcessors 方法的主要作用是将所有实现了 BeanPostProcessor 接口的类实例化,并添加到 BeanFactory 中的后置处理器列表中。这样,在 Bean 的创建过程中,Spring 容器会依次调用这些后置处理器的方法,对 Bean 进行相应的处理。这些处理器可以对 Bean 进行增强、修改属性值、解析注解等操作,以满足特定的需求。

三、onRefresh

该方法会创建 WebServer:

private void createWebServer() {
	WebServer webServer = this.webServer;
	ServletContext servletContext = getServletContext();
	if (webServer == null && servletContext == null) {
		StartupStep createWebServer = this.getApplicationStartup().start("spring.boot.webserver.create");
		ServletWebServerFactory factory = getWebServerFactory();
		createWebServer.tag("factory", factory.getClass().toString());
		this.webServer = factory.getWebServer(getSelfInitializer());
		createWebServer.end();
		getBeanFactory().registerSingleton("webServerGracefulShutdown",
				new WebServerGracefulShutdownLifecycle(this.webServer));
		getBeanFactory().registerSingleton("webServerStartStop",
				new WebServerStartStopLifecycle(this, this.webServer));
	}
	else if (servletContext != null) {
		try {
			getSelfInitializer().onStartup(servletContext);
		}
		catch (ServletException ex) {
			throw new ApplicationContextException("Cannot initialize servlet context", ex);
		}
	}
	initPropertySources();
}

四、finishBeanFactoryInitialization

finishBeanFactoryInitialization 法的作用是完成 BeanFactory 的初始化过程。在应用程序上下文启动时,会调用该方法来完成 BeanFactory 的初始化工作,包括实例化和初始化所有的非延迟加载的单例 Bean。
具体来说,finishBeanFactoryInitialization 方法会按照以下步骤完成 BeanFactory 的初始化:

  1. 实例化所有非延迟加载的单例 Bean:根据 Bean 定义信息,通过反射或其他方式实例化所有非延迟加载的单例 Bean,并将它们放入容器中。
  2. 依赖注入:对所有实例化的 Bean 进行依赖注入,即将它们所依赖的其他 Bean 注入到相应的属性中。
  3. 初始化:对所有实例化并注入依赖的 Bean 进行初始化。这包括调用 Bean 的初始化方法(如果有定义的话),以及应用任何配置的 Bean 后置处理器对 Bean 进行处理。
  4. 完成 BeanFactory 的初始化:将 BeanFactory 的状态设置为已初始化完成,标记整个初始化过程的结束。

通过调用 finishBeanFactoryInitialization 方法,Spring 容器能够确保所有非延迟加载的单例 Bean 都被正确实例化、注入依赖和初始化,从而使它们可以在应用程序中被正常使用。

五、finishRefresh

finishRefresh 方法的作用是在应用程序上下文刷新完成后执行一些额外的操作。
在应用程序上下文的刷新过程中,会调用该方法来完成一些与刷新相关的收尾工作。
具体来说,finishRefresh方法会按照以下步骤完成额外的操作:

  1. 初始化生命周期处理器:对于实现了 Lifecycle 接口的 Bean,会调用它们的 start 方法来启动这些 Bean。
  2. 发布应用程序上下文已完成事件:通过 ApplicationEventPublisher,发布一个 ContextRefreshedEvent 事件,通知其他监听器应用程序上下文已完成刷新。
  3. 注册 ApplicationListener 的 Bean:将实现了 ApplicationListener 接口的 Bean 注册到应用程序上下文中,以便监听其他事件。
  4. 初始化其他单例 Bean:对于非延迟加载的单例 Bean,会调用它们的初始化方法(如果有定义的话)。
  5. 发布应用程序上下文已启动事件:通过 ApplicationEventPublisher,发布一个 ContextStartedEvent 事件,通知其他监听器应用程序上下文已启动。

通过调用finishRefresh方法,Spring容器能够在应用程序上下文刷新完成后执行一些额外的操作,如启动生命周期处理器、发布事件等。这些操作可以用于执行一些初始化、通知或其他自定义的逻辑,以满足特定的需求。

6、总结

refresh 方法感觉还是比较难以分析,后面部分文字内容还是借鉴了 ChatGPT,感觉如果你想知道某个函数的作用时,直接问它,它或许会告诉你正确答案,比如你这样问:finishRefresh 方法的作用是啥?