一、写在前面的话

用SpringBoot 已经有很长一段时间了,在工作中也使用了SpringBoot 的一些加载机制。比如:在系统启动前后执行数据库更新文件;自定义事件后在某个时机去执行具体的业务;再有就是修改一些自动配置类等。但都没有对SpingBoot 的启动流程做总结,那么今天就来总结一下。此篇源码基于版本:spring-boot-starter-parent:2.3.4.RELEASE

二、启动流程详解

1、关键注解:@SpringBootApplication

众所周知,在 SpringBoot 启动类上都少不了此注解:

@SpringBootApplication
public class PromoteApplication {

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

查看注解源码:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
@AliasFor(annotation = EnableAutoConfiguration.class)
	Class<?>[] exclude() default {};

	
	@AliasFor(annotation = EnableAutoConfiguration.class)
	String[] excludeName() default {};

	
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
	String[] scanBasePackages() default {};

	
	@AliasFor(annotation = ComponentScan.class, attribute = "basePackageClasses")
	Class<?>[] scanBasePackageClasses() default {};

	
	@AliasFor(annotation = ComponentScan.class, attribute = "nameGenerator")
	Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;

	
	@AliasFor(annotation = Configuration.class)
	boolean proxyBeanMethods() default true;
	

其核心使用了@SpringBootConfiguration@EnableAutoConfiguration,前者的作用类似于 @Configuration 表明是一个Java 配置类。而@EnableAutoConfiguration 则是将所有符合配置条件的 Bean 都加载到 IOC 容器中。查看其源码:

  @Target(ElementType.TYPE)
  @Retention(RetentionPolicy.RUNTIME)
  @Documented
  @Inherited
  @AutoConfigurationPackage
  @Import(AutoConfigurationImportSelector.class)
  public @interface EnableAutoConfiguration {

        String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";

        Class<?>[] exclude() default {};

        String[] excludeName() default {};
  }

其核心类为:AutoConfigurationImportSelector,类图如下:

在这里插入图片描述
程序通过执行了 AutoConfigurationImportSelector.AutoConfigurationGroup.selectImports() 获取到符合条件的配置类,如下源码:

@Override
public void process(AnnotationMetadata annotationMetadata, DeferredImportSelector deferredImportSelector) {
	Assert.state(deferredImportSelector instanceof AutoConfigurationImportSelector,
			() -> String.format("Only %s implementations are supported, got %s",
					AutoConfigurationImportSelector.class.getSimpleName(),
					deferredImportSelector.getClass().getName()));
   //根据 deferredImportSelector 获取自动配置entry:
	AutoConfigurationEntry autoConfigurationEntry = ((AutoConfigurationImportSelector) deferredImportSelector)
			.getAutoConfigurationEntry(annotationMetadata);
	this.autoConfigurationEntries.add(autoConfigurationEntry);
	for (String importClassName : autoConfigurationEntry.getConfigurations()) {
		this.entries.putIfAbsent(importClassName, annotationMetadata);
	}
}

AutoConfigurationImportSelector.getAutoConfigurationEntry 的源码如下:

protected AutoConfigurationEntry getAutoConfigurationEntry(AnnotationMetadata annotationMetadata) {
	if (!isEnabled(annotationMetadata)) {
		return EMPTY_ENTRY;
	}
	//获取 @EnableAutoConfiguration 中的属性(exclude 和 excludeName)
	AnnotationAttributes attributes = getAttributes(annotationMetadata);
	//从META-INF/spring.factories 中获取自动配置类
	List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);
	//删除重复的配置
	configurations = removeDuplicates(configurations);
	Set<String> exclusions = getExclusions(annotationMetadata, attributes);
	checkExcludedClasses(configurations, exclusions);
	// 移除所有在 exclude 和 excludeName 定义的类
	configurations.removeAll(exclusions);
	configurations = getConfigurationClassFilter().filter(configurations);
	fireAutoConfigurationImportEvents(configurations, exclusions);
	return new AutoConfigurationEntry(configurations, exclusions);
	}

getCandidateConfigurations() 的源码如下, 总结起来就是通过加载 spring.factories 文件, 找出对应的配置类:

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {
	List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),
			getBeanClassLoader());
	Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "
			+ "are using a custom packaging, make sure that file is correct.");
	return configurations;
}

在这里插入图片描述
在这里插入图片描述
再回到 AutoConfigurationImportSelector.AutoConfigurationGroup.process() 中,一共过滤出了31个自动配置类:
在这里插入图片描述
执行完上述方法后,进行当前类的selectImports() :
在这里插入图片描述

2.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); //(1)
	listeners.starting(); //(2)
	try {
		ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
		ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);// (3)
		configureIgnoreBeanInfo(environment);
		Banner printedBanner = printBanner(environment);
		context = createApplicationContext(); // (4)
		exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,
				new Class[]{ConfigurableApplicationContext.class}, context);
		prepareContext(context, environment, listeners, applicationArguments, printedBanner); // (5)
		refreshContext(context);   // (6)
		afterRefresh(context, applicationArguments); // (7)
		stopWatch.stop();
		if (this.logStartupInfo) {
			new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
		}
		listeners.started(context); // (8)
		callRunners(context, applicationArguments);  // (9)
	} catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, listeners);
		throw new IllegalStateException(ex);
	}

	try {
		listeners.running(context);   // (10)
	} catch (Throwable ex) {
		handleRunFailure(context, ex, exceptionReporters, null);
		throw new IllegalStateException(ex);
	}
	return context;
}

以上执行流程可以总结为:
在这里插入图片描述

1)getRunListeners

源码如下:

SpringApplicationRunListeners listeners = getRunListeners(args);

private SpringApplicationRunListeners getRunListeners(String[] args) {
	Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
	// 此处获取SpringApplicationRunListener的实现类:EventPublishingRunListener,并返回实例。
	return new SpringApplicationRunListeners(logger,
			getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
2)listeners.starting

源码如下:

listeners.starting();
// SpringApplicationRunListeners.starting():
void starting() {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.starting();
	}
}

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

3)prepareEnvironment

准备环境:prepareEnvironment(listeners, applicationArguments);

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
	ApplicationArguments applicationArguments) {
	// 创建并配置环境
	ConfigurableEnvironment environment = getOrCreateEnvironment();
	configureEnvironment(environment, applicationArguments.getSourceArgs());
	ConfigurationPropertySources.attach(environment);
	// 调用 EventPublishingRunListener.environmentPrepared() 发布事件:ApplicationEnvironmentPreparedEvent
	listeners.environmentPrepared(environment);
	bindToSpringApplication(environment);
	if (!this.isCustomEnvironment) {
		environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment,
				deduceEnvironmentClass());
	}
	ConfigurationPropertySources.attach(environment);
	return environment;
}
4)createApplicationContext

创建一个 ConfigurableApplicationContext 子类并且实例化:

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);
}

DEFAULT_SERVLET_WEB_CONTEXT_CLASS 对应的类:
org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext, 类图为:
在这里插入图片描述

DEFAULT_REACTIVE_WEB_CONTEXT_CLASS 对应的类:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext,类图为:在这里插入图片描述
DEFAULT_CONTEXT_CLASS 对应的类:org.springframework.context.annotation.AnnotationConfigApplicationContext,类图为:
在这里插入图片描述

5)prepareContext

准备上下文,源码如下:

private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment,
			SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
	context.setEnvironment(environment);
	// 注册单例 beanNameGenerator,把ResourceLoader设置进应用上下文
	postProcessApplicationContext(context);
	// 执行初始化器
	applyInitializers(context);
	// 1) 发布事件:ApplicationPreparedEvent。看具体下文解释
	listeners.contextPrepared(context);
	if (this.logStartupInfo) {
		logStartupInfo(context.getParent() == null);
		logStartupProfileInfo(context);
	}
	// Add boot specific singleton beans
	ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
	beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
	if (printedBanner != null) {
		beanFactory.registerSingleton("springBootBanner", printedBanner);
	}
	if (beanFactory instanceof DefaultListableBeanFactory) {
		((DefaultListableBeanFactory) beanFactory)
				.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
	}
	if (this.lazyInitialization) {
		context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
	}
	// 载入资源
	Set<Object> sources = getAllSources();
	Assert.notEmpty(sources, "Sources must not be empty");
	load(context, sources.toArray(new Object[0]));
	listeners.contextLoaded(context);
}
listeners.contextPrepared(context);

//org.springframework.boot.SpringApplicationRunListeners.contextPrepared()
void contextPrepared(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.contextPrepared(context);
	}
}

// org.springframework.boot.context.event.EventPublishingRunListener.contextPrepared()
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
	
		this.initialMulticaster.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}

6)refreshContext

刷新上下文:

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
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// 为上下文刷新做准备,设置启动日期和执行标志,以及对属性资源进行初始化操作
		prepareRefresh();

		// 告诉子类,刷新内部Bean 工厂。通常留给子类自己实现 refreshBeanFactory()
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// 配置 BeanFactory 的属性,例如:类加载器或后置处理器
		prepareBeanFactory(beanFactory);

		try {
			//允许在上下文子类中对Bean 进行后置处理(修改Bean信息等)
			postProcessBeanFactory(beanFactory);

			// 在上下文中调用注册为Bean的工厂处理器
			invokeBeanFactoryPostProcessors(beanFactory);

			// 注册拦截bean创建的bean处理器。
			registerBeanPostProcessors(beanFactory);

			// 初始化上下文的消息源
			initMessageSource();

			// 初始化应用事件广播器:ApplicationEventMulticaster
			initApplicationEventMulticaster();

			// 初始化其它特殊的Bean
			onRefresh();

			// 检查并向容器注册监听器
			registerListeners();

			//实例化所有剩余的(非lazy init)单例Bean。
			finishBeanFactoryInitialization(beanFactory);

			// 结束上下文刷新,发布事件:ContextRefreshedEvent
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// 销毁已经创建的单例Bean,以避免资源占用
			destroyBeans();

			// 取消上下文刷新,重置 active 标志位
			cancelRefresh(ex);

			throw ex;
		}

		finally {
			// 重置Spring 核心缓存,特别是ReflectionUtils、AnnotationUtils、ResolvableType和CachedIntrospectionResults缓存。
			resetCommonCaches();
		}
	}
}

7)afterRefresh

空方法,在刷新完上下文后调用

protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {
}

8)listeners.started

实际是调用 org.springframework.boot.SpringApplicationRunListeners.started()


void started(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.started(context);
	}
}

再调用:org.springframework.boot.context.event.EventPublishingRunListener.started() ,发布事件:ApplicationStartedEvent


@Override
public void started(ConfigurableApplicationContext context) {
	context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
}

9)callRunners

执行 ApplicationRunnerCommandLineRunner 的实现类的 run() 可以利用两个类做系统更新的一些操作。


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

private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
	try {
		(runner).run(args);
	}
	catch (Exception ex) {
		throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
	}
}

private void callRunner(CommandLineRunner runner, ApplicationArguments args) {
	try {
		(runner).run(args.getSourceArgs());
	}
	catch (Exception ex) {
		throw new IllegalStateException("Failed to execute CommandLineRunner", ex);
	}
}

10)listeners.running

实际调用 :org.springframework.boot.SpringApplicationRunListeners.running()


void running(ConfigurableApplicationContext context) {
	for (SpringApplicationRunListener listener : this.listeners) {
		listener.running(context);
	}
}

再调用 org.springframework.boot.context.event.EventPublishingRunListener.running() ,发布事件:ApplicationReadyEvent


@Override
public void running(ConfigurableApplicationContext context) {
	context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
}

三、总结

从上述的流程图中可以看到,有部分执行过程中涉及到不同的事件发布。那么查看 org.springframework.boot.context.event.SpringApplicationEvent 的实现类,上述涉及到 6 种不同的事件:
在这里插入图片描述
Spring 事件监听使用了观察者模式。在此有三种角色:事件发布者,事件,事件对应的监听器。具体的执行原理如下:
在这里插入图片描述

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐