天天看点

Spring Boot启动流程源码分析Spring Boot启动流程源码分析

Spring Boot启动流程源码分析

版本:2.1.1.RELEASE

使用main方法启动Spring Boot应用:

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

进入SpringApplication类的run方法最终实现位置:

public ConfigurableApplicationContext run(String... args) {
	    // 1. 启动计时
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
		ConfigurableApplicationContext context = null;
		// 2. 回调接口SpringBootExceptionReporter用于支持自定义spring应用程序启动错误的报告
		Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
		// 3. 配置启用Java headless模式 
		configureHeadlessProperty();
		// 4. 获取Spring应用run方法的监听器集合并启动所有的监听器
		SpringApplicationRunListeners listeners = getRunListeners(args);
		listeners.starting();
		try {
		    // 5. 提供对用于运行SpringApplication的参数的访问
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
			// 6. 创建和配置环境
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
		    // 7. 配置忽略BeanInfo类的加载
			configureIgnoreBeanInfo(environment);
			// 8. 打印Banner
			Banner printedBanner = printBanner(environment);
			// 9. 创建ApplicationContext
			context = createApplicationContext();
			// 10. 获取异常报告实例列表
			exceptionReporters = getSpringFactoriesInstances(
					SpringBootExceptionReporter.class,
					new Class[] { ConfigurableApplicationContext.class }, context);
			// 11. 准备应用上下文
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
			// 12. 刷新底层的ApplicationContext
			refreshContext(context);
			// 13. protected方法,应用上下文刷新后,子类可实现此方法用于后续的操作
			afterRefresh(context, applicationArguments);
			// 14. 打印应用启动信息
			stopWatch.stop();
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			// 15. 启动实现了CommandLineRunner 和 ApplicationRunner 接口的类的run方法 
			listeners.started(context);
			callRunners(context, applicationArguments);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, listeners);
			throw new IllegalStateException(ex);
		}

		try {
		    // 16. 在run 方法结束之前立即调用,发布事件,应用程序已准备好接受服务请求
			listeners.running(context);
		}
		catch (Throwable ex) {
			handleRunFailure(context, ex, exceptionReporters, null);
			throw new IllegalStateException(ex);
		}
		return context;
	}
           

run方法源码上注释了大概流程,接下来继续深入重点流程的源码。

流程4,获取Spring应用run方法的监听器集合并启动所有的监听器:

getRunListeners(String[] args) 方法源码:

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

返回SpringApplicationRunListeners 实例,直接看构造方法的第二个参数的getSpringFactoriesInstances方法实现:

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		// 1. 获取类加载器
		ClassLoader classLoader = getClassLoader();
		// 2. 获取指定类型的工厂实现类的完全限定类名集合
		Set<String> names = new LinkedHashSet<>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		// 3. 根据传入的完全限定类名集合创建对应工厂实例
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
	    // 4. 根据工厂实例上的@Order注解指定的顺序排序
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
           

该方法第一个参数这里传入的是SpringApplicationRunListener 接口,会获取该接口所在类加载器下的“META-INF/spring.factories”属性文件

设置的接口实现org.springframework.boot.context.event.EventPublishingRunListener,然后调用该类的构造方法实例化:

public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}
           

该类的主要作用是作为应用启动过程的事件发布监听器,可以看到构造方法中实例化了一个简单的应用事件多播器SimpleApplicationEventMulticaster 并遍历添加应用启动事件监听器。

流程4最后调用listeners.starting() 启动监听器,实现源码:

@Override
	public void starting() {
		this.initialMulticaster.multicastEvent(
				new ApplicationStartingEvent(this.application, this.args));
	}
           

该方法多播一个ApplicationStartingEvent实例(应用启动事件),事件源是SpringApplication本身。

接下来就是解析事件类型并调用对应的事件监听器了,感兴趣的可以自己深入。深入之前需要对Spring事件机制有所了解,

推荐此文Spring事件机制。

流程6. 创建和配置环境:

prepareEnvironment(listeners, applicationArguments)方法实现:

private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// 创建环境
		ConfigurableEnvironment environment = getOrCreateEnvironment();
		// 配置环境
		configureEnvironment(environment, applicationArguments.getSourceArgs());
		// 发布环境准备事件
		listeners.environmentPrepared(environment);
		// 绑定环境到此应用
		bindToSpringApplication(environment);
		// 判断是否需要转换环境
		if (!this.isCustomEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
		}
		// 附加ConfigurationPropertySource支持到指定环境
		ConfigurationPropertySources.attach(environment);
		return environment;
	}
           

其中,getOrCreateEnvironment() 方法实现:

private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
		// 根据ClassPath存在的类推断应用运行环境,以下都是web环境
		switch (this.webApplicationType) {
		case SERVLET:
			return new StandardServletEnvironment();
		case REACTIVE:
			return new StandardReactiveWebEnvironment();
		default:
			return new StandardEnvironment();
		}
	}
           

流程9. 创建ApplicationContext:

createApplicationContext方法实现:

protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
				switch (this.webApplicationType) {
				case SERVLET:
				    // 1. 初始化并返回org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext Class对象
					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);
				}
			}
			// 忽略异常捕获代码
		}
		// 2. 调用AnnotationConfigServletWebServerApplicationContext对象的默认构造方法实例化
		return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass);
	}
           

流程11. 准备应用上下文:

prepareContext方法实现:

private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
		// 1. 设置环境
		context.setEnvironment(environment);
		// 2. 在ApplicationContext中应用任何相关的后置处理,这里为context对象的BeanFactory实例DefaultListableBeanFactory添加转换服务
		postProcessApplicationContext(context);
		// 3. 在context刷新之前应用实现了ApplicationContextInitializer回调接口的实例进行context上下文对象的初始化
		applyInitializers(context);
		// 4. 发布context初始化事件
		listeners.contextPrepared(context);
		// 5. 打印应用版本信息和激活的配置文件信息active profile
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}
		// 6. 添加名称为springApplicationArguments,springBootBanner的单例bean
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
		if (printedBanner != null) {
			beanFactory.registerSingleton("springBootBanner", printedBanner);
		}
		if (beanFactory instanceof DefaultListableBeanFactory) {
			((DefaultListableBeanFactory) beanFactory)
					.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
		}
		// 7. 加载源(即main方法所在的类对象)不可变的集合对象并注册其bean到应用上下文
		Set<Object> sources = getAllSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[0]));
		// 8. 发布应用准备事件
		listeners.contextLoaded(context);
	}
           

应用上下文对象准备好了,接下来就进行刷新上下文操作。

12. 刷新底层的ApplicationContext:

refreshContext方法实现:

private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
			    // 向JVM运行时注册一个关机钩子,在JVM关闭时同时关闭这个上下文。
				context.registerShutdownHook();
			}
			......
		}
	}
           

进入到ServletWebServerApplicationContext类的refresh(context)方法实现:

@Override
	public final void refresh() throws BeansException, IllegalStateException {
		try {
			super.refresh();
		}
		......
	}
           

发现是直接调用的父类AbstractApplicationContext的refresh方法实现:

@Override
	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// 1. 准备好刷新上下文
			prepareRefresh();

			// 2. 告诉子类刷新内部bean工厂
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 3. 准备bean工厂以用于此上下文中
			prepareBeanFactory(beanFactory);

			try {
				// 4. 允许在特定的ApplicationContext实现中注册特殊的bean后置处理器
				postProcessBeanFactory(beanFactory);

				// 5. 实例化并调用所有已注册的BeanFactoryPostProcessor bean
				invokeBeanFactoryPostProcessors(beanFactory);

				// 6. 实例化并调用所有已注册的BeanPostProcessor bean
				registerBeanPostProcessors(beanFactory);

				// 7. 初始化MessageSource用于当前上下文,提供参数化和i18n的支持
				initMessageSource();

				// 8. 初始化事件多路广播用于当前上下文,默认使用SimpleApplicationEventMulticaster单例bean
				initApplicationEventMulticaster();

				// 9. 在特定上下文子类中初始化其他特殊bean。
				onRefresh();

				// 10. 检查监听器bean并注册它们
				registerListeners();

				// 11. 实例化剩余所有非懒加载的单例bean
				finishBeanFactoryInitialization(beanFactory);

				// 12. 最后一步: 发布相应的事件
				finishRefresh();
			}
			catch (BeansException ex) {
				......
	            // 销毁所有创建的单例来避免悬空资源
				destroyBeans();
				// 重置 'active' 标识.
				cancelRefresh(ex);
				// 抛出异常给调用者
				throw ex;
			}
			finally {
				// 重置Spring的公共反射元数据缓存
				resetCommonCaches();
			}
		}
	}
           

第一点主要做了以下操作:

  • 清除本地元数据缓存(如果有的话),删除所有缓存的类元数据。
  • 设置其启动日期和活动标志以及执行任何属性源的初始化。

第二点主要做了以下操作:

  • 将成员变量 refreshed 设为 true。
  • 为 DefaultListableBeanFactory 指定一个用于序列化的id。

第三点主要做了以下操作:

  • 配置工厂的标准上下文特征,例如上下文的类加载器和后置处理程序。
  • 所有bean定义都已加载,但还没有实例化bean。

第四点主要做了以下操作:

  • 注册特定应用上下文的后置处理器bean
  • 扫描basePackage指定的包路径
  • 注册被注解的类,例如@Configuration

第五点主要做了以下操作:

  • 实例化并调用所有已注册的BeanFactoryPostProcessor bean,如果给定显式顺序,则遵循显式顺序
  • 分别调用实现了BeanFactoryPostProcessor接口的bean。

第六点主要做了以下操作:

  • 实例化并调用所有已注册的BeanPostProcessor bean,如果给定显式顺序,则遵循显式顺序
  • 分别调用实现了BeanPostProcessor接口的bean。

第九点主要做了以下操作:

  • 默认创建TomcatWebServer
  • 初始化WebApplicationContext和SerlvetContext参数

第十一点完成BeanFactory的初始化并实例化剩余的单例bean:

finishBeanFactoryInitialization方法实现:

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
		// 初始化用于此上下文的转换服务
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
				beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
			beanFactory.setConversionService(
					beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
		}

		// 如果没有内嵌value解析器Bean则注册一个(例如 PropertyPlaceholderConfigurer bean),主要用于解析${}占位符.
		if (!beanFactory.hasEmbeddedValueResolver()) {
			beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
		}
		
		// 尽早地初始化LoadTimeWeaverAware bean以允许尽早地注册其变换器
		String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
		for (String weaverAwareName : weaverAwareNames) {
			getBean(weaverAwareName);
		}

		// 停止正用于类型匹配的临时类加载器
		beanFactory.setTempClassLoader(null);

		// 缓存所有bean定义的元数据,不接受后面的改变
		beanFactory.freezeConfiguration();

		// 实例化所有剩余的(非懒加载)单例bean
		beanFactory.preInstantiateSingletons();
	}
           

其中重点看最后一步preInstantiateSingletons方法的实现:

@Override
	public void preInstantiateSingletons() throws BeansException {
        ......
        
		// 迭代一个beanDefinitionNames的副本以允许init方法,这些方法又轮流注册新的bean定义。
		// 虽然这可能不是常规工厂引导程序的一部分,但它确实可以正常工作。
		List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

		// 触发所有非懒加载单例bean的初始化...
		for (String beanName : beanNames) {
			RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
			// 如果不是抽象的bean并且是非懒加载的单例bean,则进行
			if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
			    // 判断是否是FactoryBean,如果是则进一步判断是否需要尽早的初始化bean,否则直接初始化bean
				if (isFactoryBean(beanName)) {
					Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
					if (bean instanceof FactoryBean) {
						final 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);
				}
			}
		}

		// 触发所有可用单例bean的afterSingletonsInstantiated方法回调...
		for (String beanName : beanNames) {
			Object singletonInstance = getSingleton(beanName);
			if (singletonInstance instanceof SmartInitializingSingleton) {
				final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
				if (System.getSecurityManager() != null) {
					AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
						smartSingleton.afterSingletonsInstantiated();
						return null;
					}, getAccessControlContext());
				}
				else {
					smartSingleton.afterSingletonsInstantiated();
				}
			}
		}
	}
           

接下来看getBean(beanName)方法的底层实现,是直接调用doGetBean方法,返回指定bean的实例,该实例可以是共享的或独立的:

protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
        // 1. 返回bean名称,必要时删除工厂前缀,并将别名解析为规范名称。
		final String beanName = transformedBeanName(name);
		Object bean;

		// 2. 急切地检查单例缓存以手动地注册单例
		Object sharedInstance = getSingleton(beanName);
		// 共享的单例bean实例不为空并且args为空
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
			    // 3. 判断该当前bean是否在创建中
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			//  4. 获取给定bean实例的对象,如果是FactoryBean,则为bean实例本身或其创建的对象。
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}

		else {
		    // 其它情况暂不做深入研究,感兴趣的读者可以自行阅读AbstractBeanFactory#doGetBean方法源码
		    ......
        }
		return (T) bean;
	}
           

查看第二点getSingleton方法的实现:

@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		// 如果从singletonObjects单例bean缓存中获取key为beanName的单例bean为空并且该单例bean
		// 当前在创建中(在整个工厂内)则从早期已实例化的单例bean缓存earlySingletonObjects中
		// 检查beanName的单例对象,如果为空则进一步从singletonFactories单例工厂缓存中获取beanName为key
		// 的BeanFactory,如果BeanFactory不为空则获取到其管理的单例bean实例并将其缓存
		// 到earlySingletonObjects对象上,最后从singletonFactories缓存中移除管理该beanName
		// 实例的BeanFactory对象(解决循环引用)
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
           

几个重要对象说明:

  • singletonObjects:单例bean对象的缓存,ConcurrentHashMap->{beanName:beanInstance}
  • earlySingletonObjects: 早期的单例bean对象的缓存,HashMap->{beanName:beanInstance}
  • singletonFactories:单例BeanFactory的缓存,HashMap->{beanName:beanFactory}, beanFactory->beanInstance

回到refresh方法的第十二点,最后完成上下文的刷新操作,调用LifecycleProcessor的onRefresh方法并且发布最终的ContextRefreshedEvent事件:

protected void finishRefresh() {
		// 清除此资源加载器中的所有资源缓存。
		clearResourceCaches();

		// 初始化此上下文的生命周期处理器DefaultLifecycleProcessor。
		initLifecycleProcessor();

		// 调用DefaultLifecycleProcessor的onRefresh方法
		getLifecycleProcessor().onRefresh();

		// 发布最终的ContextRefreshedEvent事件
		publishEvent(new ContextRefreshedEvent(this));

		// 如果激活则参与到LiveBeansView MBean中
		LiveBeansView.registerApplicationContext(this);
	}
           

子类finishRefresh方法最后启动相应的WebServer并发布事件。

@Override
	protected void finishRefresh() {
		super.finishRefresh();
		WebServer webServer = startWebServer();
		if (webServer != null) {
			publishEvent(new ServletWebServerInitializedEvent(webServer, this));
		}
	}
           

以上就是Spring Boot启动流程源码分析的完整内容,如果有问题欢迎提出!

继续阅读