SpringApplication最主要的作用就是根据环境配置构建一个ApplicationContext上下文。上下文类型分为
public enum WebApplicationType {NONE, SERVLET, REACTIVE }
public class SpringApplication {// 默认IOC容器使用的上下文public static final String DEFAULT_CONTEXT_CLASS = "org.springframework.context."+ "annotation.AnnotationConfigApplicationContext";// web 基于注解容器使用的上下文public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework.boot."+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";// 可以配置为Web容器的类条件列表private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };// web 基于Reactive使用的上下文public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";private static final String REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework."+ "web.reactive.DispatcherHandler";// spring mvc使用的Servletprivate static final String MVC_WEB_ENVIRONMENT_CLASS = "org.springframework."+ "web.servlet.DispatcherServlet";// banner 文件位置public static final String BANNER_LOCATION_PROPERTY_VALUE = SpringApplicationBannerPrinter.DEFAULT_BANNER_LOCATION;public static final String BANNER_LOCATION_PROPERTY = SpringApplicationBannerPrinter.BANNER_LOCATION_PROPERTY;//Headless模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。private static final String SYSTEM_PROPERTY_JAVA_AWT_HEADLESS = "java.awt.headless";private boolean headless = true;private static final Log logger = LogFactory.getLog(SpringApplication.class);private Set<Class<?>> primarySources;//设置配置源,注意配置源可以多个// can be: a class name, package name, or an XML resource location.private Set<String> sources = new LinkedHashSet<>();// 引导类private Class<?> mainApplicationClass;// banner输出模式private Banner.Mode bannerMode = Banner.Mode.CONSOLE;private boolean logStartupInfo = true;private boolean addCommandLineProperties = true;private Banner banner;private ResourceLoader resourceLoader;private BeanNameGenerator beanNameGenerator;// IOC容器环境上下文private ConfigurableEnvironment environment;// IOC上下文使用的类private Class<? extends ConfigurableApplicationContext> applicationContextClass;// 容器模式private WebApplicationType webApplicationType;private boolean registerShutdownHook = true;// 准备好环境上下文,刷新容器之前的初始化回调接口private List<ApplicationContextInitializer<?>> initializers;// SpringApplication启动事件监听器private List<ApplicationListener<?>> listeners;// 默认配置private Map<String, Object> defaultProperties;// profilesprivate Set<String> additionalProfiles = new HashSet<>();}
构造方法初始化
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
// 构造方法初始化
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 设置primarySources
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断容器类型
this.webApplicationType = deduceWebApplicationType();
// SPI加载 ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// SPI加载 ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断main方法所在的类
this.mainApplicationClass = deduceMainApplicationClass();
}
private WebApplicationType deduceWebApplicationType() {
// 根据ClassPath下是否有相关类
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
// 有AnnotationConfigReactiveWebServerApplicationContext
// 且没有DispatcherServlet
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
// 指定的类都没有
// Servlet, ConfigurableWebApplicationContext
return WebApplicationType.NONE;
}
}
// 默认Web容器
return WebApplicationType.SERVLET;
}
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
// 根据main方法,但是不严谨
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
SpringApplication的构造方法主要做了几件事:
- 设置引导类为主加载类,方便包扫描范围
- 推断容器类型,根据classpath下类的存在情况
- SPI加载ApplicationContextInitializer并设置到字段中
- SPI加载ApplicationListener并设置到字段中
-
开始运行
构造完
SpringApplication对象后,就是开始运行,并创建IOC容器了public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args); listeners.starting(); try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); // 准备环境上下文,这里很重要,做了很多事,加载各种配置等 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments); // 配置 configureIgnoreBeanInfo(environment); // 打印Banner Banner printedBanner = printBanner(environment); // 根据类型,创建Spring IOC容器 context = createApplicationContext(); exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context); // 准备IOC容器基本信息 prepareContext(context, environment, listeners, applicationArguments, printedBanner); // 启动容器,调用refresh方法 refreshContext(context); // 启动完成后事件发布 afterRefresh(context, applicationArguments); // stopWatch.stop(); if (this.logStartupInfo) { new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } // 发布事件 listeners.started(context); // 调用ApplicationRunner和CommandLineRunner接口钩子方法 callRunners(context, applicationArguments); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { // 发布运行中事件 listeners.running(context); } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } // 返回IOC容器句柄 return context; }准备Env上下文
prepareEnvironment(listeners, applicationArguments)
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
// Create and configure the environment
// 新建一个Environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
// 配置环境,添加默认配置源,设置env profiles
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 发布事件
listeners.environmentPrepared(environment);
// 设置到SpringApplication#
bindToSpringApplication(environment);
// 转换环境上下文
if (this.webApplicationType == WebApplicationType.NONE) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
// 待分析
ConfigurationPropertySources.attach(environment);
return environment;
}
// 创建环境上下文
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
// 根据容器类型创建对应的环境上下文
switch (this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
// 配置环境上下文
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
// 配置defaultProperties
configurePropertySources(environment, args);
// 配置profiles
configureProfiles(environment, args);
}
// 配置默认属性
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
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("springApplicationCommandLineArgs", args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
// 设置Profiles
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<>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(StringUtils.toStringArray(profiles));
}
发布ApplicationEnvironmentPreparedEvent事件
根据spring.factories文件配置的ApplicationListener,执行环境上下文准备妥当事件,在这些监听器中,有ConfigFileApplicationListener解析application.properties配置文件的监听器,还有诸如解析bootstrap.properties配置文件的BootstrapApplicationListener监听器
