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使用的Servlet
private 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;
// profiles
private 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
监听器