解读Spring Boot启动过程之二:Web工程启动的主干流程

main入口

@SpringBootApplication
public class MyApplication {

	public static void main(String[] args) {
		// 执行SpringAppllication的静态run方法
		SpringApplication.run(MyApplication.class, args);

	}

}

在Application的静态run方法内创建了SpringApplication实例,并调用了实例方法run


	public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		// 首先,创建SpringApplication实例
		return new SpringApplication(primarySources)
				// 然后,调用其run方法
				.run(args);
	}

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));
		// 推断当前应用程序的类型
		// 是Servlet? 还是Reactive?
		this.webApplicationType = WebApplicationType.deduceFromClasspath();

		// 从META-INF/spring.factories中加载BootstrapRegistryInitializer的实例
		this.bootstrapRegistryInitializers = new ArrayList<>(
				getSpringFactoriesInstances(BootstrapRegistryInitializer.class));

		// 从META-INF/spring.factories中加载ApplicationContextInitializer的实例
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
		
		// 从META-INF/spring.factories中加载ApplicationListener的实例
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
		
		// 推断main方法所在的类
		this.mainApplicationClass = deduceMainApplicationClass();
	}

调用SpringApplication实例的run方法

	public ConfigurableApplicationContext run(String... args) {
		SpringApplicationHooks.hooks().preRun(this);
		long startTime = System.nanoTime();
		// 引导器 上下文
		DefaultBootstrapContext bootstrapContext = createBootstrapContext();
		
		ConfigurableApplicationContext context = null;
		
		// 配置Headless属性
		configureHeadlessProperty();
		
		// 从META-INF/spring.factories中加载SpringApplicationRunListener的实例,并封装到SpringApplicationRunListeners对象当中
		SpringApplicationRunListeners listeners = getRunListeners(args);
		
		// 监听器广播事件:开始启动中
		listeners.starting(bootstrapContext, this.mainApplicationClass);
		try {
			// 将运行参数 封装进ApplicationArguments中
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
			// 准备 Environment
			ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
			configureIgnoreBeanInfo(environment);
			
			// 打印Banner
			Banner printedBanner = printBanner(environment);
			
			// 创建 应用上下文。若是Servlet应用,则返回AnnotationConfigSerlvetWebServerApplicationContext的实例。
			context = createApplicationContext();
			context.setApplicationStartup(this.applicationStartup);
			
			// 准备 应用上下文
			prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
			if (refreshContext(context)) { // 刷新Context,若执行刷新成功,则返回true
				// 在Context刷新后,默认是空方法
				afterRefresh(context, applicationArguments);
				
				Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
				if (this.logStartupInfo) {
					new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(),
							timeTakenToStartup);
				}
				// 广播事件:已启动
				listeners.started(context, timeTakenToStartup);
				
				// 调用 Runner,包括CommandLineRunner和ApplicationRunner的实例
				callRunners(context, applicationArguments);
			}
		}
		catch (Throwable ex) {
			// 处理异常
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}
		try {
			if (context.isRunning()) {
				Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
				listeners.ready(context, timeTakenToReady);
			}
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		SpringApplicationHooks.hooks().postRun(this, context);
		return context;
	}

内置Tomcat(Jetty、undertow等)启动

创建ApplicationContext对象。

在run方法中,以下行创建了ApplicationContext对象。

			// 创建 应用上下文。若是Servlet应用,则返回AnnotationConfigSerlvetWebServerApplicationContext的实例。
			context = createApplicationContext();

实际返回的 是 ApplicationContext的子类AnnotationConfigServletWebServerApplicationContext的实例

调用ApplicationContext的refresh()

创建AppliationContext之后,在run方法中,执行了refreshContext方法

			if (refreshContext(context)) { // 刷新Context,若执行刷新成功,则返回true

进入refreshContext,跟踪后,发现最终调用了ApplicationContext的refresh方法

	protected void refresh(ConfigurableApplicationContext applicationContext) {
		// 调用ApplicationContext的refresh方法
		applicationContext.refresh();
	}

下面先看下 AnnotationConfigServletWebServerApplicationContext的继承结构
image

refresh方法是由其父类 AbstractApplicationContext实现的。
下面的refresh()方法,重点关注方法中的 onRefresh()那一行

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

			// 为刷新做一些准备工作
			prepareRefresh();

			// 获取一个新鲜的BeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 为BeanFactory的使用做一些准备工作
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				// 留给子类,对BeanFactory作工作
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
				// 调用BeanFactoryPostProcessor
				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.
				// =========== 注意:为子类准备的方法,用于初始化特殊的bean
				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) {
				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...
				resetCommonCaches();
				contextRefresh.end();
			}
		}
	}

而AnnotationConfigServletWebServerApplicationContext的直接父类ServletWebServerApplicationContext重写了onRefresh方法

调用onRefresh方法

image

createWebServer()

可以看到,其中的createWebServer()便是用于创建及启动内嵌Tomcat的了~~

posted @ 2022-06-24 17:53  i初学者  阅读(286)  评论(0编辑  收藏  举报