SpringApplication:
1、SpringApplication基本使用:
1.1 SpringApplication运行
SpringApplication.run(DemoSpringBootApplication.class, args)
1.2、自定义SpringApplication
1)通过SpringApplicationAPI
方式
SpringApplication springApplication = new SpringApplication(DemoSpringBootApplication.class);
springApplication.setBannerMode(Banner.Mode.CONSOLE);
springApplication.setWebApplicationType(WebApplicationType.NONE);
springApplication.setAdditionalProfiles("prod");
springApplication.setHeadless(true);
2)通过SpringApplicationBuilderAPI
方式
new SpringApplicationBuilder(DemoSpringBootApplication.class)
.bannerMode(Banner.Mode.CONSOLE)
.web(WebApplicationType.NONE)
.profiles("prod")
.headless(true)
.run(args);
2、SpringApplication准备阶段:
package org.springframework.boot;
public class SpringApplication {
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 配置源
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 推断应用类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 通过工厂方式,加载实例。在后面的运行阶段(run方法)来操作。
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// 通过工厂方式,加载实例。在后面的运行阶段(run方法)来操作。
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 推断当前主类,通过线程的栈来推断。
this.mainApplicationClass = deduceMainApplicationClass();
}
}
2.1 配置 Spring Boot Bean 源
Java 配置 Class 或 XML 上下文配置文件集合,用于 `Spring Boot BeanDefinitionLoader`读取,并且将配置源解析加载为Spring Bean 定义
package org.springframework.boot;
class BeanDefinitionLoader {
//...省略
// bean定义注册, 一个或多个
BeanDefinitionLoader(BeanDefinitionRegistry registry, Object... sources) {
Assert.notNull(registry, "Registry must not be null");
Assert.notEmpty(sources, "Sources must not be empty");
this.sources = sources;
// java class或者bean或者 xml
this.annotatedReader = new AnnotatedBeanDefinitionReader(registry);
this.xmlReader = new XmlBeanDefinitionReader(registry);
if (isGroovyPresent()) {
this.groovyReader = new GroovyBeanDefinitionReader(registry);
}
this.scanner = new ClassPathBeanDefinitionScanner(registry);
this.scanner.addExcludeFilter(new ClassExcludeFilter(sources));
}
}
配置 Class
Java 配置 Class用于 Spring 注解驱动中 Java 配置类,大多数情况是 Spring 模式注解所标注的类,如`@Configuration`。
XML 上下文配置文件用于 Spring 传统配置驱动中的 XML 文件。
XML 上下文配置文件
package com.example.springbootlearn.demospringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication}
*
*/
@SpringBootApplication
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(SpringApplicationBootstrap.class, args);
}
}
在SpringApplication的run方法中,要传入标了@SpringBootApplication的类。不一定是主类。比如下面这样也可以:
package com.example.springbootlearn.demospringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* {@link SpringApplication}
*
*/
public class SpringApplicationBootstrap {
public static void main(String[] args) {
SpringApplication.run(ApplicationConfiguration.class, args);
}
@SpringBootApplication
public static class ApplicationConfiguration {
}
}
也可以这样:
package com.example.springbootlearn.demospringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.HashSet;
import java.util.Set;
/**
* {@link SpringApplication}
*
*/
public class SpringApplicationBootstrap {
public static void main(String[] args) {
// SpringApplication.run(ApplicationConfiguration.class, args);
Set<String> sources = new HashSet<>();
sources.add(ApplicationConfiguration.class.getName());
SpringApplication springApplication = new SpringApplication();
springApplication.setSources(sources);
springApplication.run(args);
}
@SpringBootApplication
public static class ApplicationConfiguration {
}
}
setSources方法:
package org.springframework.boot;
public class SpringApplication {
// ...省略
/**
* Set additional sources that will be used to create an ApplicationContext. A source
* 可以是:
* can be: a class name, package name, or an XML resource location.
* <p>
* Sources set here will be used in addition to any primary sources set in the
* constructor.
* @param sources the application sources to set
* @see #SpringApplication(Class...)
* @see #getAllSources()
*/
public void setSources(Set<String> sources) {
Assert.notNull(sources, "Sources must not be null");
this.sources = new LinkedHashSet<>(sources);
}
}
2.2 推断 Web 应用类型
根据当前应用 ClassPath 中是否存在相关实现类来推断 Web 应用的类型,包括:
Web Reactive:WebApplicationType.REACTIVE
Web Servlet:WebApplicationType.SERVLET
非 Web:WebApplicationType.NONE
推断方法:
package org.springframework.boot.test.context;
public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstrapper {
// ... 省略
private WebApplicationType deduceWebApplicationType() {
if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null) // REACTIVE_WEB_ENVIRONMENT_CLASS = "org.springframework." + "web.reactive.DispatcherHandler";
&& !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null) // MVC_WEB_ENVIRONMENT_CLASS = "org.springframework." + "web.servlet.DispatcherServlet";
&& !ClassUtils.isPresent(JERSEY_WEB_ENVIRONMENT_CLASS, null)) {
// JERSEY_WEB_ENVIRONMENT_CLASS = "org.glassfish.jersey.server.ResourceConfig";
return WebApplicationType.REACTIVE;
}
for (String className : WEB_ENVIRONMENT_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
}
2.3 推断引导类(Main Class):
package org.springframework.boot;
public class SpringApplication {
// ... 省略
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
for (StackTraceElement stackTraceElement : stackTrace) {
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
}
catch (ClassNotFoundException ex) {
// Swallow and continue
}
return null;
}
}
2.4 加载应用上下文初始器ApplicationContextInitializer
通过Spring 工厂加载机制,实例化 ApplicationContextInitializer
实现类,并排序对象集合。
package org.springframework.boot;
public class SpringApplication {
// ... 省略
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = getClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
}
上面代码中:SpringFactoriesLoader.loadFactoryNames
方法,
- 通过类:
org.springframework.core.io.support.SpringFactoriesLoader
实现。 - 会去读取配置资源:
META-INF/spring.factories
- 排序:
AnnotationAwareOrderComparator.sort(instances)
参考:
在org.springframework.boot.autoconfigure的spring.factories
中,可以看到应用上下文初始配置。
自定义:
在resources目录下新建META-INF文件,在META-INF下新建spring.factories
文件。
spring.factories
:
# 实际顺序与order有关,与这里配置顺序无关。
# Initializers
org.springframework.context.ApplicationContextInitializer=\
com.example.springbootlearn.context.AfterDemoApplicationContextInitializer,\
com.example.springbootlearn.context.DemoApplicationContextInitializer
新建content文件夹,新建DemoApplicationContextInitializer文件。
DemoApplicationContextInitializer
:
package com.example.springbootlearn.context;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
*
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DemoApplicationContextInitializer<C extends ConfigurableApplicationContext> implements ApplicationContextInitializer<C> {
@Override
public void initialize(C applicationContext) {
System.out.println("ConfigurableApplicationContext.id = :" + applicationContext.getId());
}
}
新建AfterDemoApplicationContextInitializer
文件:
package com.example.springbootlearn.context;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.Ordered;
public class AfterDemoApplicationContextInitializer implements ApplicationContextInitializer, Ordered {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("after applicationContext.id = " + applicationContext.getId());
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
SpringApplicationBootstrap
:
package com.example.springbootlearn.demospringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.HashSet;
import java.util.Set;
/**
* {@link SpringApplication}
*
*/
public class SpringApplicationBootstrap {
public static void main(String[] args) {
// SpringApplication.run(ApplicationConfiguration.class, args);
Set<String> sources = new HashSet<>();
sources.add(ApplicationConfiguration.class.getName());
SpringApplication springApplication = new SpringApplication();
springApplication.setSources(sources);
springApplication.setWebApplicationType(WebApplicationType.NONE); // web和非web都会输出
springApplication.run(args);
}
@SpringBootApplication
public static class ApplicationConfiguration {
}
}
运行结果:
// ... 省略
ConfigurableApplicationContext.id = :org.springframework.context.annotation.AnnotationConfigApplicationContext@22702006
after applicationContext.id = application
// ... 省略
2.5 加载应用事件监听器( ApplicationListener)
通过Spring 工厂加载机制,实例化 ApplicationListener
实现类,并排序对象集合。
参考:
自定义:
创建listernr文件夹,在新建一个DemoApplicationListener
类:
DemoApplicationListener
:
package com.example.springbootlearn.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/**
* Demo {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}
*
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DemoApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("demo ... : " + event.getApplicationContext().getId()
+ ",timestamp : " + event.getTimestamp());
}
}
创建AfterDemoApplicationListener
:
package com.example.springbootlearn.listener;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.Ordered;
/**
* After Demo {@link ApplicationListener} 监听 {@link ContextRefreshedEvent}
*/
public class AfterDemoApplicationListener implements ApplicationListener<ContextRefreshedEvent>, Ordered {
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
// #监听事件要一样 进行order排序
System.out.println("after demo ... : " + event.getApplicationContext().getId()
+ ",timestamp : " + event.getTimestamp());
}
@Override
public int getOrder() {
return Ordered.LOWEST_PRECEDENCE;
}
}
SpringApplicationBootstrap
:
package com.example.springbootlearn.demospringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.util.HashSet;
import java.util.Set;
/**
* {@link SpringApplication}
*
*/
public class SpringApplicationBootstrap {
public static void main(String[] args) {
// SpringApplication.run(ApplicationConfiguration.class, args);
Set<String> sources = new HashSet<>();
sources.add(ApplicationConfiguration.class.getName());
SpringApplication springApplication = new SpringApplication();
springApplication.setSources(sources);
springApplication.run(args);
}
@SpringBootApplication
public static class ApplicationConfiguration {
}
}
运行结果:
demo ... : application,timestamp : 1612591318234
after demo ... : application,timestamp : 1612591318234
3、SpringApplication 运行阶段
3.1 加载与运行SpringApplication 运行(run)监听器
main方法调用SpringApplication的run方法。
springApplication.run(args);
public static void main(String[] args) {
// SpringApplication.run(ApplicationConfiguration.class, args);
Set<String> sources = new HashSet<>();
sources.add(ApplicationConfiguration.class.getName());
SpringApplication springApplication = new SpringApplication();
springApplication.setSources(sources);
springApplication.run(args);
}
类:SpringApplication
:
package org.springframework.boot;
public class SpringApplication {
//... 省略
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
// 加载监听器。通过Spring 工厂加载机制,读取 SpringApplicationRunListener 对象集合
SpringApplicationRunListeners listeners = getRunListeners(args);
// 运行监听器。
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
Banner printedBanner = printBanner(environment);
context = createApplicationContext();
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] {
ConfigurableApplicationContext.class }, context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
listeners.started(context);
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);
}
return context;
}
}
SpringApplicationRunListener
监听多个运行状态方法:
监听方法 | 阶段说明 | Spring Boot Since版本 |
---|---|---|
starting() | Spring 应用刚启动 | 1.0 |
environmentPrepared(ConfigurableEnvironment) | ConfigurableEnvironment 准备妥当,允许将其调整 | 1.0 |
contextPrepared(ConfigurableApplicationContext) | ConfigurableApplicationContext 准备妥当,允许将其调整 | 1.0 |
contextLoaded(ConfigurableApplicationContext) | ConfigurableApplicationContext 已装载,但仍未启动 | 1.0 |
started(ConfigurableApplicationContext) | ConfigurableApplicationContext 已启动,此时 Spring Bean 已初始化完成 | 2.0 |
running(ConfigurableApplicationContext) | Spring 应用正在运行 | 2.0 |
failed(ConfigurableApplicationContext,Throwable) | Spring 应用运行失败 | 2.0 |
3.2 监听 事件
springboot 通过 SpringApplicationRunListener
的实现类 EventPublishingRunListener
。
通过 Spring Framework 事件,API 来广播 Spring Boot 事件。
1)spring事件
public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster {
// ... 省略
// 广播
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
Executor executor = getTaskExecutor();
// 异步或同步
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
}
Spring 应用事件
普通应用事件: ApplicationEvent
应用上下文事件: ApplicationContextEvent
Spring 应用监听器
接口编程模型: ApplicationListener
注解编程模型: @EventListener
Spring 应用事广播器
接口: ApplicationEventMulticaster
实现类: SimpleApplicationEventMulticaster
参考:
在spring-boot-2.1.0.RELEASE-sources.jar/META-INF/spring.factories文件中:
自定义一个:
在com.example.springbootlearn新建一个run包
新建一个DemoRunListener
类:
package com.example.springbootlearn.run;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationRunListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
public class DemoRunListener implements SpringApplicationRunListener {
public DemoRunListener(SpringApplication application, String[] args) {
}
@Override
public void starting() {
System.out.println("DemoRunListener:starting()......");
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
}
@Override
public void contextPrepared(ConfigurableApplicationContext context) {
}
@Override
public void contextLoaded(ConfigurableApplicationContext context) {
}
@Override
public void started(ConfigurableApplicationContext context) {
}
@Override
public void running(ConfigurableApplicationContext context) {
}
@Override
public void failed(ConfigurableApplicationContext context, Throwable exception) {
}
}
运行结果:
发现比banner打印还早。
DemoRunListener:starting()......
banner打印
// ... 省略
这是因为SpringApplication
的run
方法:
package org.springframework.boot;
public class SpringApplication {
// ... 省略
public ConfigurableApplicationContext run(String... args) {
// ...省略
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try{
// ...省略
Banner printedBanner = printBanner(environment);
}
// ...省略
}
}
EventPublishingRunListener
监听方法与 Spring Boot 事件对应关系
监听方法 | springboot 事件 | springboot since版本 |
---|---|---|
starting() | ApplicationStartingEvent | 1.5 |
environmentPrepared(ConfigurableEnvironment) | ApplicationEnvironmentPreparedEvent | 1.0 |
contextPrepared(ConfigurableApplicationContext) | ||
contextLoaded(ConfigurableApplicationContext) | ApplicationPreparedEvent | 1.0 |
started(ConfigurableApplicationContext) | ApplicationStartedEvent | 2.0 |
running(ConfigurableApplicationContext) | ApplicationReadyEvent | 2.0 |
failed(ConfigurableApplicationContext,Throwable) | ApplicationFailedEvent | 1.0 |
2) 监听springboot事件
在spring-boot-2.1.0.RELEASE.jar/META-INF/spring.factoires
中,
参考:org.springframework.boot.context.config.ConfigFileApplicationListener
自定义:
在com.example.springbootlearn.listener包下,新建一个BeforeConfigFileApplicationListener
文件。
BeforeConfigFileApplicationListener
:
package com.example.springbootlearn.listener;
import org.springframework.boot.context.config.ConfigFileApplicationListener;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.boot.context.event.ApplicationPreparedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.event.SmartApplicationListener;
import org.springframework.core.Ordered;
import org.springframework.core.env.Environment;
/**
* before {@link ConfigFileApplicationListener} 实现
*/
public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered {
// Order值越小,优先级越高。所以 这里 比 ConfigFileApplicationListener 优先级高
@Override
public int getOrder() {
return ConfigFileApplicationListener.DEFAULT_ORDER - 1;
}
@Override
public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {
return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)
|| ApplicationPreparedEvent.class.isAssignableFrom(eventType);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ApplicationEnvironmentPreparedEvent) {
ApplicationEnvironmentPreparedEvent preparedEvent = (ApplicationEnvironmentPreparedEvent)event;
Environment environment = preparedEvent.getEnvironment();
System.out.println("environment.getProperty(\"name\") :" + environment.getProperty("name"));
}
if (event instanceof ApplicationPreparedEvent) {
}
}
}
spring.factories
:
# Application Listeners
org.springframework.context.ApplicationListener=\
com.example.springbootlearn.listener.BeforeConfigFileApplicationListener
application.properties
:
name = learndemo
运行结果:
//... 省略
environment.getProperty("name") :null
// ... 省略
调整一下order值,将上面代码的order修改一下:
@Override
public int getOrder() {
return ConfigFileApplicationListener.DEFAULT_ORDER + 1;
}
运行输出:
// ...省略
environment.getProperty("name") :learndemo
// ...省略
3.3 创建 Spring 应用上下文
Web Reactive: AnnotationConfigReactiveWebServerApplicationContext // package org.springframework.boot.web.reactive.context;
Web Servlet: AnnotationConfigServletWebServerApplicationContext // package org.springframework.boot.web.servlet.context;
非 Web: AnnotationConfigApplicationContext // package org.springframework.context.annotation;
参考:
package org.springframework.boot;
public class SpringApplication {
public ConfigurableApplicationContext run(String... args) {
// ...省略
ConfigurableApplicationContext context = null;
try {
// ... 省略
context = createApplicationContext();
// ... 省略
}
// ... 省略
}
}
createApplicationContext()
:
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);
}
自定义:
package com.example.springbootlearn.demospringboot;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Spring 应用上下文 引导类
*/
@SpringBootApplication
public class SpringApplicationContextBootstrap {
public static void main(String[] args) {
// web servlet或web Reactive 或非web
ConfigurableApplicationContext context = new SpringApplicationBuilder(SpringApplicationContextBootstrap.class)
// .web(WebApplicationType.NONE) // web servlet或web Reactive 或非web
.run(args);
System.out.println("ConfigurableApplicationContext 类型:" +
context.getClass().getName());
// 关闭上下文
context.close();
}
}
运行结果:
当web = WebApplicationType.SERVLET
:
// ... 省略
ConfigurableApplicationContext 类型:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
// ... 省略
当web = WebApplicationType.NONE
:
// ... 省略
ConfigurableApplicationContext 类型:org.springframework.context.annotation.AnnotationConfigApplicationContext
// ... 省略
当web =WebApplicationType.REACTIVE
:
// ... 省略
ConfigurableApplicationContext 类型:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
// ... 省略
3.4 创建 Environment
根据准备阶段的推断 Web 应用类型创建对应的 ConfigurableEnvironment
实例:
Web Reactive: StandardEnvironment
Web Servlet: StandardServletEnvironment
非 Web: StandardEnvironment
package com.example.springbootlearn.demospringboot;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.context.ConfigurableApplicationContext;
/**
* Spring 应用上下文 引导类
*/
@SpringBootApplication
public class SpringApplicationContextBootstrap {
public static void main(String[] args) {
ConfigurableApplicationContext context = new SpringApplicationBuilder(SpringApplicationContextBootstrap.class)
// .web(WebApplicationType.NONE) // web servlet或web Reactive 或非web
.run(args);
System.out.println("ConfigurableApplicationContext 类型:" +
context.getClass().getName());
// Environment
System.out.println("Environment 类型:" +
context.getEnvironment().getClass().getName());
// 关闭上下文
context.close();
}
}
运行结果:
当.web(WebApplicationType.NONE)
:
ConfigurableApplicationContext 类型:org.springframework.context.annotation.AnnotationConfigApplicationContext
Environment 类型:org.springframework.core.env.StandardEnvironment
当.web(WebApplicationType.REACTIVE)
:
ConfigurableApplicationContext 类型:org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext
Environment 类型:org.springframework.boot.web.reactive.context.StandardReactiveWebEnvironment
当.web(WebApplicationType.SERVLET)
:
ConfigurableApplicationContext 类型:org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext
Environment 类型:org.springframework.web.context.support.StandardServletEnvironment
SpringApplication上下文周期来逐一调用,把相应的资源准备好。
package org.springframework.boot;
public class SpringApplication {
// ... 省略
// SpringApplication上下文周期来逐一调用,把相应的资源准备好。
public ConfigurableApplicationContext run(String... args) {
// ... 省略
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// ... 省略
}
private ConfigurableEnvironment prepareEnvironment(
// ... 省略
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment); // 监听
// ... 省略
}
}