个人觉得这个也很重要的,顺便在这里参考“芋艿“的博客深入学习下底层源码,然后再配合一张图来帮助理解记忆。咱们的Spring Boot版本是1.5.9,所以您的版本里源码实现可能会有区别,但我觉得不同版本的Spring Boot整体思想应该差不多。

构造器

// sources数组仅仅包含一个元素: DemoApplication.class	
public SpringApplication(Object... sources) {
		initialize(sources);
	}
	
 private void initialize(Object[] sources) {
		if (sources != null && sources.length > 0) {
			this.sources.addAll(Arrays.asList(sources));
		}
     	// 判断是否是web环境,不同的spring boot版本,实现可能不一样
		this.webEnvironment = deduceWebEnvironment();
     	
     	// 设置ApplicationContextInitializer 
		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
     	// ApplicationListener List
		setListeners((Collection) 
                     getSpringFactoriesInstances(ApplicationListener.class));
     	
		this.mainApplicationClass = deduceMainApplicationClass();
}

	public void setInitializers(
			Collection<? extends ApplicationContextInitializer<?>> initializers) {
		this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
		this.initializers.addAll(initializers);
	}
	
	public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
		this.listeners = new ArrayList<ApplicationListener<?>>();
		this.listeners.addAll(listeners);
	}


	// 下面是SpringApplication 类的一些属性

	private ConfigurableEnvironment environment;

	private Class<? extends ConfigurableApplicationContext> applicationContextClass;

	private boolean webEnvironment;

	private List<ApplicationContextInitializer<?>> initializers;

	private List<ApplicationListener<?>> listeners;

复制代码

![](liutianruo-2019-go-go-go.oss-cn-shanghai.aliyuncs.com/notes/02_Sp… Application构造器.png)

run()

这就是启动Spring Boot最核心的代码了,正菜来了哦。

	public ConfigurableApplicationContext run(String... args) {
        // 用来配合日志统计启动时间的
		StopWatch stopWatch = new StopWatch();
		stopWatch.start();
        
		ConfigurableApplicationContext context = null;
		FailureAnalyzers analyzers = null;
        // awt相关,可忽略
		configureHeadlessProperty();
        // 获得 SpringApplicationRunListeners(封装了多个SpringApplicationRunListener) 
		SpringApplicationRunListeners listeners = getRunListeners(args);
        // 启动监听
		listeners.starting();
        
		try {
            //创建  ApplicationArguments 对象
			ApplicationArguments applicationArguments = new DefaultApplicationArguments(
					args);
            	
            //  加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置
			ConfigurableEnvironment environment = prepareEnvironment(listeners,
					applicationArguments);
            // 不重要,就控制台显示 Spring Boot 图案的,吉祥物属于是
			Banner printedBanner = printBanner(environment);
            // Spring上下文
			context = createApplicationContext();
            // 异常报告器
			analyzers = new FailureAnalyzers(context);
            // 调用所有初始化类的 initialize
			prepareContext(context, environment, listeners, applicationArguments,
					printedBanner);
            // 初始化spring上下文
			refreshContext(context);
            //执行 Spring 上下文的初始化的后置逻辑
			afterRefresh(context, applicationArguments);
            // 通知***,spring上下文启动完成
			listeners.finished(context, null);
            // 统计时长结束
			stopWatch.stop();
            
			if (this.logStartupInfo) {
				new StartupInfoLogger(this.mainApplicationClass)
						.logStarted(getApplicationLog(), stopWatch);
			}
			return context;
		}
		catch (Throwable ex) {
			handleRunFailure(context, listeners, analyzers, ex);
			throw new IllegalStateException(ex);
		}
	}
复制代码

SpringApplicationRunListeners

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


复制代码

getSpringFactoriesInstances

		private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
			Class<?>[] parameterTypes, Object... args) {
		ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
		// Use names and ensure unique to protect against duplicates
		Set<String> names = new LinkedHashSet<String>(
				SpringFactoriesLoader.loadFactoryNames(type, classLoader));
		List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
				classLoader, args, names);
		AnnotationAwareOrderComparator.sort(instances);
		return instances;
	}
复制代码

SpringFactoriesLoader获取META-INF/spring.factories配置的SpringApplicationRunListener实现类对应的全类名,这里会用Set来去重。

org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
复制代码
	SpringApplicationRunListeners(Log log,
			Collection<? extends SpringApplicationRunListener> listeners) {
		this.log = log;
		this.listeners = new ArrayList<SpringApplicationRunListener>(listeners);
	}
复制代码

拿到了SpringApplicationRunListener实现类后,就被SpringApplicationRunListeners作为一个List封装了起来。

EventPublishingRunListener

本质就是一个事件广播器,只是封装了一下而已,最后去处理事件的还是ApplicationListener。只能说EventPublishingRunListener只是一个花钱找别人写代码的码农罢了,好吧,那SpringApplicationRunListeners就是公司老板了。哈哈

public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {

	private final SpringApplication application;

	private final String[] args;
	
	private final SimpleApplicationEventMulticaster initialMulticaster;

	public EventPublishingRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
        // 获取SpringApplication构造器里封装的ApplicationListener List,
        // 并将List注入给impleApplicationEventMulticaster
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}
复制代码

SimpleApplicationEventMulticaster才是底层的事件监听打工仔,可真能藏,小伙计。

看一下EvenPublishingRunListener关于事件的处理吧。

	@Override
	@SuppressWarnings("deprecation")
	public void starting() {
        //直接广播事件去了
		this.initialMulticaster
				.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
	}

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

我们来验证下吧

SpringApplicationRunListeners#starting

	public void starting() {
        // 目前仅有一个内部实现EventPublishingRunListener
		for (SpringApplicationRunListener listener : this.listeners) {
			listener.starting();
		}
	}
复制代码
  • SpringApplicationRunListeners.starting

    • SpringApplicationRunListener.starting

      • EventPublishingRunListener
        • SimpleApplicationEventMulticaster.multicastEvent
          • List<ApplicationListener>
      	@Override
      	public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) {
      		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
      		for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
      			Executor executor = getTaskExecutor();
      			if (executor != null) {
      				executor.execute(new Runnable() {
      					@Override
      					public void run() {
      						invokeListener(listener, event);
      					}
      				});
      			}
      			else {
      				invokeListener(listener, event);
      			}
      		}
      	}
      复制代码

留一张图吧:

至此,***(实际是广播器,最惨的是ApplicationListener了,封装了那么多层,结果还是我来处理,妈的)的内裤,我们是扒的差不多了。

ConfigurableEnvironment

	private ConfigurableEnvironment prepareEnvironment(
			SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments) {
		// Create and configure the environment
		ConfigurableEnvironment environment = getOrCreateEnvironment();
        
		configureEnvironment(environment, applicationArguments.getSourceArgs());
        
		listeners.environmentPrepared(environment);
        
		if (!this.webEnvironment) {
			environment = new EnvironmentConverter(getClassLoader())
					.convertToStandardEnvironmentIfNecessary(environment);
		}
        
		return environment;
	}
复制代码

getOrCreateEnvironment

	private ConfigurableEnvironment getOrCreateEnvironment() {
		if (this.environment != null) {
			return this.environment;
		}
        // 如果是Web环境,就创建StandardServletEnvironment
		if (this.webEnvironment) {
			return new StandardServletEnvironment();
		}
		return new StandardEnvironment();
	}
复制代码

注意:我们的Spring Boot版本只有1.5,底层的Spring Framework版本是4.3,因此没有WebFlux(Since 5.0),所以就没有StandardReactiveWebEnvironment

configureEnvironment

	protected void configureEnvironment(ConfigurableEnvironment environment,
			String[] args) {
		configurePropertySources(environment, args);
		configureProfiles(environment, args);
	}
复制代码

configurePropertySources

MutablePropertySources

	protected void configurePropertySources(ConfigurableEnvironment environment,
			String[] args) {
		MutablePropertySources sources = environment.getPropertySources();
        
        // 配置defaultProperties
		if (this.defaultProperties != null && !this.defaultProperties.isEmpty()) {
			sources.addLast(
					new MapPropertySource("defaultProperties", this.defaultProperties));
		}
        // 启动参数的属性源
		if (this.addCommandLineProperties && args.length > 0) {
			String name = CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME;
            // 已存在,就进行替换
			if (sources.contains(name)) {
				PropertySource<?> source = sources.get(name);
				CompositePropertySource composite = new CompositePropertySource(name);
				composite.addPropertySource(new SimpleCommandLinePropertySource(
						name + "-" + args.hashCode(), args));
				composite.addPropertySource(source);
				sources.replace(name, composite);
			}
			else {
                // 不存在,就进行添加
				sources.addFirst(new SimpleCommandLinePropertySource(args));
			}
		}
	}
复制代码

private boolean addCommandLineProperties = true;

是否添加JVM启动参数,默认是添加

configureProfiles

	protected void configureProfiles(ConfigurableEnvironment environment, String[] args) {
		environment.getActiveProfiles(); // ensure they are initialized
		// But these ones should go first (last wins in a property key clash)
		Set<String> profiles = new LinkedHashSet<String>(this.additionalProfiles);
		profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
		environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
	}
复制代码

再给一张图

![](liutianruo-2019-go-go-go.oss-cn-shanghai.aliyuncs.com/notes/02_Sp… Application Environment.png)

createApplicationContext

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

	private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
			"org.springframework.web.context.ConfigurableWebApplicationContext" };

 protected ConfigurableApplicationContext createApplicationContext() {
		Class<?> contextClass = this.applicationContextClass;
		if (contextClass == null) {
			try {
                // 根据反射获取Class对象
				contextClass = Class.forName(this.webEnvironment
						? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
			}
			catch (ClassNotFoundException ex) {
				throw new IllegalStateException(
						"Unable create a default ApplicationContext, "
								+ "please specify an ApplicationContextClass",
						ex);
			}
		}
        //根据Class对象实例化ConfigurableApplicationContext对象
		return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
	}
复制代码

prepareContext

	private void prepareContext(ConfigurableApplicationContext context,
			ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
			ApplicationArguments applicationArguments, Banner printedBanner) {
        // ApplicationContext关联Environment
		context.setEnvironment(environment);
        // 设置 context 的一些属性
		postProcessApplicationContext(context);
        // 初始化 ApplicationContextInitializer
		applyInitializers(context);
        
		listeners.contextPrepared(context);
		if (this.logStartupInfo) {
			logStartupInfo(context.getParent() == null);
			logStartupProfileInfo(context);
		}

		// Add boot specific singleton beans 设置 beanFactory 的属性
		context.getBeanFactory().registerSingleton("springApplicationArguments",
				applicationArguments);
		if (printedBanner != null) {
			context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
		}

		// Load the sources
        // 加载 BeanDefinition 
		Set<Object> sources = getSources();
		Assert.notEmpty(sources, "Sources must not be empty");
		load(context, sources.toArray(new Object[sources.size()]));
		listeners.contextLoaded(context);
	}
复制代码

setEnvironment

设置ApplicationContextEnvironment属性。

postProcessApplicationContext

设置ApplicationContext的一些属性

	protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
		if (this.beanNameGenerator != null) {
			context.getBeanFactory().registerSingleton(
					AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR,
					this.beanNameGenerator);
		}
		if (this.resourceLoader != null) {
			if (context instanceof GenericApplicationContext) {
				((GenericApplicationContext) context)
						.setResourceLoader(this.resourceLoader);
			}
			if (context instanceof DefaultResourceLoader) {
				((DefaultResourceLoader) context)
						.setClassLoader(this.resourceLoader.getClassLoader());
			}
		}
	}
复制代码

applyInitializers

	protected void applyInitializers(ConfigurableApplicationContext context) {
		for (ApplicationContextInitializer initializer : getInitializers()) {
            // 校验 ApplicationContextInitializer 的泛型非空
			Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
					initializer.getClass(), ApplicationContextInitializer.class);
			Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
            // ApplicationContextInitializer执行初始化逻辑
			initializer.initialize(context);
		}
	}
复制代码

getInitializers

		setInitializers((Collection) getSpringFactoriesInstances(
				ApplicationContextInitializer.class));
复制代码

SpringApplication的构造器实现中,初始化了ApplicationContextInitializer,怎么初始化的,从META-INF/spring.factories中遍历属性为org.springframework.context.ApplicationContextInitializer对应的属性值。

refreshContext

启动Spring容器

	private void refreshContext(ConfigurableApplicationContext context) {
		refresh(context);
		if (this.registerShutdownHook) {
			try {
				context.registerShutdownHook();
			}
			catch (AccessControlException ex) {
				// Not allowed in some environments.
			}
		}
	}
	protected void refresh(ApplicationContext applicationContext) {
		Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
		((AbstractApplicationContext) applicationContext).refresh();
	}	
复制代码

org.springframework.context.support.AbstractApplicationContext#refresh

看到了吧,Spring Boot只是封装了API而已,对于Environment做了自定义创建、还设置了ApplicationContext的一些属性、回调ApplicationContextInitializer实现,最后启动容器还是要借助Spring Framework中的AbstractApplicationContext.refresh来完成。

包括事件监听也是的,最后实际去监听的ApplicationListener也是来自于Spring Framework,所以扒皮Spring Boot源码,扒到后面,就是Spring Framework本身了。

afterRefresh

callRunners

	private void callRunners(ApplicationContext context, ApplicationArguments args) {
		List<Object> runners = new ArrayList<Object>();
		runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
		runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
		AnnotationAwareOrderComparator.sort(runners);
		for (Object runner : new LinkedHashSet<Object>(runners)) {
			if (runner instanceof ApplicationRunner) {
				callRunner((ApplicationRunner) runner, args);
			}
			if (runner instanceof CommandLineRunner) {
				callRunner((CommandLineRunner) runner, args);
			}
		}
	}
复制代码
  • ApplicationRunner
  • CommandLineRunner

这两个接口执行回调方法

一张图总结

![](liutianruo-2019-go-go-go.oss-cn-shanghai.aliyuncs.com/notes/02_Sp… Application完整.png)


作者:刘天若
链接:https://juejin.cn/post/7042483096444370958
如果你觉得本文对你有帮助,麻烦转发加关注