(一)SpringBoot源码解析----启动过程refresh()方法详解

时间:2024-04-10 19:05:25

spring版本: 5.0.6
springboot版本: 2.0.2
先祭出一张 spring 容器的核心接口图:

(一)SpringBoot源码解析----启动过程refresh()方法详解

spring 容器有两个核心接口:BeanFactory 和 ApplicationContext,其中 ApplicationContext是 BeanFactory的子类, 这两个类生成并管理 spring 容器中的 bean。但是大多数情况都是用ApplicationContext作为spring 的容器。 spring mvc和 spring boot 都是通过 applicationContext作为管理 bean 的容器的。 其中 spring boot 默认使用的是AnnotationConfigServletWebServerApplicationContext(还可以使用AnnotationConfigReactiveWebServerApplicationContext,有兴趣的同学可以研究一下,什么情况下会使用这个。), spring boot 类似 spring mvc都是 web server, 因此使用" servlet application context"作为默认容器十分可以理解。AnnotationConfigServletWebServerApplicationContext本身是一个 BeanFactory的派生类,而它的父 context 也会持有一个 BeanFactory。

再来说说启动过程:

springboot 的启动入口是 SpringApplication run方法,代码如下:

public ConfigurableApplicationContext run(String... args) {
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		configureHeadlessProperty();
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
			configureIgnoreBeanInfo(environment);
			Banner printedBanner = printBanner(environment);
          //此处创建 context
			context = createApplicationContext();
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
          //初始化context 的核心逻辑都在这行代码里。
			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;
	}

再具体分析下 refreshContext的代码逻辑

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
//清除缓存,并读取配置文件里的环境变量
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
                       // 此处的 bean factory 是通过父类GenericApplicationContext 初始化的 DefaultListableBeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
// 配置 beanFactory, 包括注册(第一次) BeanPostProcessor, 设置 classLoader等等。
// BeanPostProcessor 有两个主要的方法:postProcessBeforeInitialization 和 postProcessAfterInitialization 。 
// 这个两个方法分别的执行时期是 bean 初始化之前和初始化之后。具体的执行时期后面会说到

			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
//为 applicationContext的子类注册(第二次)个性化的 BeanPostProcessor
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
//执行 context 中注册的 BeanFactoryPostProcessor中的postProcessBeanFactory() 方法,BeanFactoryPostProcessor只有这一个方法
//BeanFactoryPostProcessor 是 bean 属性处理容器。即管理 bean工厂中的BeanDefinition, 
// BeanDefinition在 spring mvc 中就是 xml 文件中对应的 bean 标签(注意,是标签,而不是真实的 JAVA BEAN)。
//可以看到,此处已经 invoke 了postProcessBeanFactory() 方法。 而 BeanPostProcessor 的方法还没有被调用,
//所以 BeanFactoryPostProcessor的执行是要早于BeanPostProcessor的。
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
//再次注册BeanPostProcessor(这已经是第三次注册,
// 第一注册的是AbstractApplicationContext中用到的 processor, 
// 第二次为ServletWebServerApplicationContext 注册 processor)。
// 这次是为实际用到的 context注册 processor(spring boot 即是AnnotationConfigServletWebServerApplicationContext),
// 并为根据优先级和 order 排序。
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
// 实例化并注册 MessageSource类。MessageSource是国际化相关的接口
				initMessageSource();

				// Initialize event multicaster for this context.
//初始化spring 事件广播器,ApplicationContext会通过广播器发送事件,负责监听广播器的 listener 会负责处理事件
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
// 在一些特殊的 ApplicationContext子类中实例化一些特殊的 bean. 
//例如ServletWebServerApplicationContext(AnnotationConfigServletWebServerApplicationContext的父类)会初始化TomcatWebServer,
//并启动这个 server,在 spring boot 工程中,相当于启动了整个 spring boot 项目。
				onRefresh();

				// Check for listener beans and register them.
//为ApplicationEventMulticaster注册监听 listener(ApplicationListener), 
//会有一些默认的 listener被注册。例如这是一个 dubbo provider的工程,就会注册DubboBannerApplicationListener 
// 同时也会有一些自定义的 listener.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
//终于到了初始 java bean 的阶段, 注意此处只初始化单例的 bean, 并且非懒加载的类(默认即非懒加载)。
//虽然此时 java bean已经实例化,但是其依赖自动注入的 bean却不再此时注入,而是等到用到的时候再去获取,
//所以这里不会出现循环依赖的问题。
// 一个 spring bean 的初始化过程如下:
//        1. 执行构造器
//        2. BeanPostProcessor的postProcessBeforeInitialization方法
//        3. InitializingBean的afterPropertiesSet方法
//        4,@Bean注解的initMethod方法
//        5,BeanPostProcessor的postProcessAfterInitialization方法
//        6,DisposableBean的destroy方法
//        7,@Bean注解的destroyMethod方法
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
//实例化LifecycleProcessor并执行其 onRefresh()方法,刷新上下文,启动一些需要在初始化阶段启动的类(实现了Lifecycle接口的类)
// 发布ContextRefreshedEvent事件,这个应该是表示上下文启动完成的事件
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + 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...
//清理单例 bean 的元数据缓存。
				resetCommonCaches();
			}
		}
	}

至此, spring boot的启动过程就完成了, 基于篇幅和时间问题。其中还有很多代码细节没有仔细分析,这些就留给未来吧。

整个过程分析下来发现这个启动过程会有几个核心接口(应该也是 spring 整个 ioc机制的核心接口)

  1. BeanFactory
  2. ApplicationContext
  3. BeanPostProcessor
  4. BeanFactoryPostProcessor
  5. ApplicationEventMulticaster
  6. BeanDefinition
  7. LifecycleProcessor

以及每个接口里面的方法及其执行时序。
弄清楚每一个接口的原理和具体使用场景,对我们使用和理解 spring 至关重要。