springboot启动流程

springboot启动概述

一、前言

  • 个人能力尚浅,请各位大佬多多包含。
    本文针对springboot启动流程,先看run方法
@SpringBootApplication
public class VinbomDataCleanApplication {

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

二、springApplication的初始化
首先看下SpringApplication#run(java.lang.Class<?>[], java.lang.String[]) 方法

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
		return new SpringApplication(primarySources).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));
                // 初始化环境。环境分为三种:NONE(非web环境)、SERVLET(web服务)、REACTIVE(嵌入式响应式web服务),默认就是SERVLET
		this.webApplicationType = WebApplicationType.deduceFromClasspath();
                //应用上下文初始化,加载spring.factories文件。这里是首次加载,并设置了ApplicationContextInitializer
		setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
                //初始化监听器,加载spring.factories文件,并设置ApplicationListener
		setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
                //设置启动类信息
		this.mainApplicationClass = deduceMainApplicationClass();
	}

三、SpringApplication.run方法流程

public ConfigurableApplicationContext run(String... args) {
                // 开启启动时间监控
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
                // 准备ApplicationContext
		ConfigurableApplicationContext context = null;
                // 设置一些系统配置
		configureHeadlessProperty();
                // 获取spring中的监听器,这里是从spring.factories中获取的,默认取的是springframework.boot.SpringApplicationRunListener 为key,获取到的监听器类型为 EventPublishingRunListener。
		SpringApplicationRunListeners listeners = getRunListeners(args);
                // 开启监听事件
		listeners.starting();
		try {
                        // 封装参数
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
                        // 构造容器环境,并将容器中的配置信息赋值到environment 中
			ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
                        // 配置BeanInfo的忽略 :“spring.beaninfo.ignore”,值为“true”表示跳过对BeanInfo类的搜索
			configureIgnoreBeanInfo(environment);
                        // 打印信息对象
			Banner printedBanner = printBanner(environment);
                        // 创建应用上下文对象
			context = createApplicationContext();
                        // 准备上下文
			prepareContext(context, environment, listeners, applicationArguments, printedBanner);
                        // 刷新上下文
			refreshContext(context);
                        // 结束刷新,扩展功能,并未实现什么
			afterRefresh(context, applicationArguments);
                        // 计时结束
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
			}
                        // 发送上下文刷新结束后事件
			listeners.started(context);
                        // 调用ApplicationRunner和CommandLineRunner各自的run方法
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, listeners);
			throw new IllegalStateException(ex);
		}

		try {
                        // 发送容器运行事件
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}

四、流程具体步骤详解
1、获取监听器

// 获取spring中的监听器,这里是从spring.factories中获取的,默认取的是springframework.boot.SpringApplicationRunListener 为key,获取到的监听器类型为 EventPublishingRunListener。
SpringApplicationRunListeners listeners = getRunListeners(args);

其详细代码如下:

private SpringApplicationRunListeners getRunListeners(String[] args) {
		Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
		return new SpringApplicationRunListeners(logger,
				getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
	}

其中getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args)方法返回的是Collection,说明SpringApplicationRunListeners类并非是一个监听器,而是包含了一个监听器集合,默认情况下仅有一个EventPublishingRunListener。

总结:spring启动时,通过spring.factories文件中获取监听器集合。默认类型为EventPublishingRunListener。在事件发生时EventPublishingRunListener会寻找容器中的ApplicationListener的bean,并进行事件通知。

2、环境变量构造

ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);

其具体方法如下

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
                // 获取或者创建environment,web服务获取StandardServletEnvironment类型
		ConfigurableEnvironment environment = getOrCreateEnvironment();
                // 将入参配置到环境中
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		ConfigurationPropertySources.attach(environment);
                // 发送环境准备事件
		listeners.environmentPrepared(environment);
		bindToSpringApplication(environment);
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
					deduceEnvironmentClass());
		}
		ConfigurationPropertySources.attach(environment);
		return environment;
	}

2.1 application.yml的加载
listeners.environmentPrepared(environment);会发送环境准备事件,环境准备事件有多个监听器,其中ConfigFileApplicationListener监听器完成的是springboot的配置文件application.yml或application.properties文件的加载。

首先看下ConfigFileApplicationListener类中的onApplicationEvent方法

@Override
	public void onApplicationEvent(ApplicationEvent event) {
		if (event instanceof ApplicationEnvironmentPreparedEvent) {
			onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event);
		}
		if (event instanceof ApplicationPreparedEvent) {
			onApplicationPreparedEvent(event);
		}
	}

再看下EventPublishingRunListener类中的environmentPrepared方法,这里定义了ApplicationEnvironmentPreparedEvent事件

@Override
	public void environmentPrepared(ConfigurableEnvironment environment) {
		this.initialMulticaster
				.multicastEvent(new ApplicationEnvironmentPreparedEvent(this.application, this.args, environment));
	}

所以我们这里会调用ConfigFileApplicationListener类中的onApplicationEnvironmentPreparedEvent方法

private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
                // 加载EnvironmentPostProcessor集合,也是在spring.factories文件中获取
		List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();
                // 将本身添加到环境后置处理器集合中
		postProcessors.add(this);
		AnnotationAwareOrderComparator.sort(postProcessors);
                // 排序后调用EnvironmentPostProcessor类中的postProcessEnvironment方法
		for (EnvironmentPostProcessor postProcessor : postProcessors) {
			postProcessor.postProcessEnvironment(event.getEnvironment(), event.getSpringApplication());
		}
	}

接下来看下ConfigFileApplicationListener类中的postProcessEnvironment方法,该方法就加载了springboot配置文件

public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
		addPropertySources(environment, application.getResourceLoader());
	}


protected void addPropertySources(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
		RandomValuePropertySource.addToEnvironment(environment);
                //此处就是加载配置文件
		new Loader(environment, resourceLoader).load();
	}

3、创建上下文

context = createApplicationContext();

其详细内容

	/**
	 * The class name of application context that will be used by default for non-web
	 * environments.
	 */
	public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."
			+ "annotation.AnnotationConfigApplicationContext";

	/**
	 * The class name of application context that will be used by default for web
	 * environments.
	 */
	public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
			+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";

	/**
	 * The class name of application context that will be used by default for reactive web
	 * environments.
	 */
	public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
			+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";


protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
					contextClass = Class.forName(DEFAULT_SERVLET_WEB_CONTEXT_CLASS);
					break;
				case REACTIVE:
					contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS);
					break;
				default:
					contextClass = Class.forName(DEFAULT_CONTEXT_CLASS);
				}
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, please specify an ApplicationContextClass", ex);
			}
		}
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

很明显,因为我们知道webApplicationType值是servlet,所以这里创建的是AnnotationConfigServletWebServerApplicationContext类型的上下文

  • 这里需要注意:
    AnnotationConfigServletWebServerApplicationContext 构造函数中会创建 AnnotatedBeanDefinitionReader。而在 AnnotatedBeanDefinitionReader 构造函数中会调用 AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);,该方法将一些必要Bean(如ConfigurationClassPostProcessor、AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor 等)注入到了容器中。

4、上下文准备

prepareContext(context, environment, listeners, applicationArguments, printedBanner);

具体内容如下:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
                // 设置上下文环境变量
		context.setEnvironment(environment);
               // 执行容器后置处理 : 可以注册beanName策略生成器、设置资源加载器,设置转换服务等。但这里默认是没有做任何处理。目的是留给后续可以扩展
		postProcessApplicationContext(context);
		// 处理所有的初始化类的初始化方法。即 spring.factories 中key 为 org.springframework.context.ApplicationContextInitializer 指向的类,调用其 initialize 方法
		applyInitializers(context);
                // 向监听器发送容器准备事件
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// Add boot specific singleton beans
                // 获取上下文中的 BeanFactory。这里的BeanFactory 实际类型是  DefaultListableBeanFactory。BeanFactory 在初始化的时候,直接在构造函数里创建为 DefaultListableBeanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
                // 注册 springApplicationArguments等一系列bean
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
                         // 设置是否允许bean定义覆盖
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
                // 如果允许懒加载,则添加对应的BeanFactory后置处理器
		if (this.lazyInitialization) {
			context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
		}
		// Load the sources
                // 这里加载的实际上是启动类
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
                // 这里将启动类加入到 beanDefinitionMap 中,为后续的自动化配置做好了基础
		load(context, sources.toArray(new Object[0]));
                // 发送容器加载完成事件
		listeners.contextLoaded(context);
	}



        // 需要注意这里的 sources参数实际上是 启动类的 Class
	protected void load(ApplicationContext context, Object[] sources) {
		if (logger.isDebugEnabled()) {
			logger.debug("Loading source " + StringUtils.arrayToCommaDelimitedString(sources));
		}
		// 从上下文中获取 BeanDefinitionRegistry并依次创建出 BeanDefinitionLoader 。这里将sources作为参数保存到了 loader  中。也就是 loader  中保存了 启动类的Class信息
		BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
		if (this.beanNameGenerator != null) {
			loader.setBeanNameGenerator(this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			loader.setResourceLoader(this.resourceLoader);
		}
		if (this.environment != null) {
			loader.setEnvironment(this.environment);
		}
		loader.load();
	}

这里比较关键的就是loader.load(),其中不管怎么跳转都会跳转到BeanDefinitionLoader.load()

private int load(Class<?> source) {
		if (isGroovyPresent() && GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
			// Any GroovyLoaders added in beans{} DSL can contribute beans here
			GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source, GroovyBeanDefinitionSource.class);
			load(loader);
		}
                // 判断该bean是否符合注册条件
		if (isEligible(source)) {
			this.annotatedReader.register(source);
			return 1;
		}
		return 0;
	}

this.annotatedReader.register方法 后续会跳转到 AnnotatedBeanDefinitionReader.doRegisterBean 方法中,看名字就知道是这个方法的工作是 注册 Bean。实际上,在这个方法中完成了对@Qualifier 以及一些其他注解的处理。具体如下:

// 这里的 beanClass 其实就是启动类的 beanClass 
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
			@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
			@Nullable BeanDefinitionCustomizer[] customizers) {
                // 将Class转换成一个BeanDefinition类
		AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
                //判断是够应该跳过
		if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
			return;
		}
              
		abd.setInstanceSupplier(supplier);
                // 保存其作用域信息,这里默认是singleton
		ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
		abd.setScope(scopeMetadata.getScopeName());
                // 获取bean名称
		String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
		// 处理一些通用的注解信息,包括Lazy、Primary、DependsOn、Role、Description 注解。获取其value值并保存到 abd 中
		AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
                // 处理  @Qualifier 
		if (qualifiers != null) {
			for (Class<? extends Annotation> qualifier : qualifiers) {
				if (Primary.class == qualifier) {
					abd.setPrimary(true);
				}
				else if (Lazy.class == qualifier) {
					abd.setLazyInit(true);
				}
				else {
					abd.addQualifier(new AutowireCandidateQualifier(qualifier));
				}
			}
		}
		if (customizers != null) {
			for (BeanDefinitionCustomizer customizer : customizers) {
				customizer.customize(abd);
			}
		}

		BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
                // 判断是否需要创建代理
		definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
                // 将definitionHolder注册到BeanDefinitionBean中,此时的this.registry就是AnnotationConfigApplicationContext,在BeanDefinitionLoader 初始化的时候保存的
                DefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
	}

5、刷新上下文

refreshContext(context);

其详细代码如下:

private void refreshContext(ConfigurableApplicationContext context) {
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
                // 刷新上下文,springboot到此结束将工作信息交给spring
		refresh((ApplicationContext) context);
	}

调用AbstractApplicationContext#refresh方法,做了以下操作

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
                        /**
			 * 刷新上下文环境
			 * 初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验
			 * 如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,
			 * 重写initPropertySources方法就好了
			*/
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
                        /**
			 * 初始化BeanFactory
			 */
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
                        
			// Prepare the bean factory for use in this context.
                        /**
			 * 为上下文准备BeanFactory,即对BeanFactory的各种功能进行填充,如常用的注解@Autowired @Qualifier等
			 * 设置SPEL表达式#{key}的解析器
			 * 设置资源编辑注册器,如PerpertyEditorSupper的支持
			 * 添加ApplicationContextAwareProcessor处理器
			 * 在依赖注入忽略实现*Aware的接口,如EnvironmentAware、ApplicationEventPublisherAware等
			 * 注册依赖,如一个bean的属性中含有ApplicationEventPublisher(beanFactory),则会将beanFactory的实例注入进去
			 */
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.                     
                                /**
				 * 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
				 */
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
                                /**
				 * 激活各种BeanFactory处理器,包括BeanDefinitionRegistryBeanFactoryPostProcessor和普通的BeanFactoryPostProcessor
				 * 执行对应的postProcessBeanDefinitionRegistry方法 和  postProcessBeanFactory方法
				 */
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
                                /**
				 * 注册拦截Bean创建的Bean处理器,即注册BeanPostProcessor,不是BeanFactoryPostProcessor,注意两者的区别
				 * 注意,这里仅仅是注册,并不会执行对应的方法,将在bean的实例化时执行对应的方法
				 */
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
                                /**
				 * 初始化上下文中的资源文件,如国际化文件的处理等
				 */
				initMessageSource();

				// Initialize event multicaster for this context.
                                /**
				 * 初始化上下文事件广播器,并放入applicatioEventMulticaster,如ApplicationEventPublisher
				 */
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
                                /**
				 * 给子类扩展初始化其他Bean
				 */
				onRefresh();

				// Check for listener beans and register them.
                                /**
				 * 在所有bean中查找listener bean,然后注册到广播器中
				 */
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
                                /**
				 * 设置转换器
				 * 注册一个默认的属性值解析器
				 * 冻结所有的bean定义,说明注册的bean定义将不能被修改或进一步的处理
				 * 初始化剩余的非惰性的bean,即初始化非延迟加载的bean
				 */
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
                                /**
				 * 初始化生命周期处理器DefaultLifecycleProcessor,DefaultLifecycleProcessor含有start方法和stop方法,spring启动的时候调用start方法开始生命周期,
				 * spring关闭的时候调用stop方法来结束生命周期,通常用来配置后台程序,启动有一直运行,如一直轮询kafka
				 * 启动所有实现了Lifecycle接口的类
				 * 通过spring的事件发布机制发布ContextRefreshedEvent事件,以保证对应的监听器做进一步的处理,即对那种在spring启动后需要处理的一些类,这些类实现了
				 * ApplicationListener<ContextRefreshedEvent> ,这里就是要触发这些类的执行(执行onApplicationEvent方法)另外,spring的内置Event有ContextClosedEvent、ContextRefreshedEvent、ContextStartedEvent、ContextStoppedEvent、RequestHandleEvent
				 * 完成初始化,通知生命周期处理器lifeCycleProcessor刷新过程,同时发出ContextRefreshEvent通知其他人
				 */
				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();
			}
		}
	}
posted @ 2023-03-29 10:07  Be_Your_Sun  阅读(61)  评论(0编辑  收藏  举报