Spring Boot应用启动流程

Spring Boot应用启动流程

调用SpringApplication的静态run方法

1
2
3
4
5
6
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}

实际上是new了一个SpringApplication的实例

Create a new SpringApplication instance. The application context will load beans from the specified primary sources (see class-level documentation for details. The instance can be customized before calling run(String…).

创建一个新的SpringApplication实例。应用程序上下文将从指定的主要源加载bean(有关详细信息,请参阅类级文档)。可以在调用run(String…)之前定制实例。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class SpringApplication {
public static ConfigurableApplicationContext run(Class<?> primarySource,
String... args) {
return run(new Class<?>[] { primarySource }, args);
}
public static ConfigurableApplicationContext run(Class<?>[] primarySources,
String[] args) {
return new SpringApplication(primarySources).run(args);
}
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
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();
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
}

WebApplicationType

SpringApplication详细构造方法中的代码片段
this.webApplicationType = WebApplicationType.deduceFromClasspath();
从classpath中来推断出web应用类型

WebApplicationType web应用可能类型的枚举

  • NONE 应用不应当以一个web应用来运行也不应该启动一个嵌入式的web服务器
  • SERVLET 应用程序应该作为一个基于servlet的web应用程序运行,并应该启动一个嵌入式servlet web服务器
  • REACTIVE 应用程序应作为一个反应性web应用程序运行,并应启动一个嵌入式反应性web服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/**
* An enumeration of possible types of web application.
*
* @author Andy Wilkinson
* @author Brian Clozel
* @since 2.0.0
*/
public enum WebApplicationType {
/**
* The application should not run as a web application and should not start an
* embedded web server.
*/
NONE,
/**
* The application should run as a servlet-based web application and should start an
* embedded servlet web server.
*/
SERVLET,
/**
* The application should run as a reactive web application and should start an
* embedded reactive web server.
*/
REACTIVE;
private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
private static final String WEBMVC_INDICATOR_CLASS = "org.springframework."
+ "web.servlet.DispatcherServlet";
private static final String WEBFLUX_INDICATOR_CLASS = "org."
+ "springframework.web.reactive.DispatcherHandler";
private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
return WebApplicationType.REACTIVE;
}
for (String className : SERVLET_INDICATOR_CLASSES) {
if (!ClassUtils.isPresent(className, null)) {
return WebApplicationType.NONE;
}
}
return WebApplicationType.SERVLET;
}
...
}

Determine whether the Class identified by the supplied name is present and can be loaded. Will return false if either the class or one of its dependencies is not present or cannot be loaded.
确定由提供的名称标识的类是否存在并可以加载。如果类或其依赖项之一不存在或无法加载,则返回false。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class ClassUtils {
public static boolean isPresent(String className, @Nullable ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
}
catch (IllegalAccessError err) {
throw new IllegalStateException("Readability mismatch in inheritance hierarchy of class [" +
className + "]: " + err.getMessage(), err);
}
catch (Throwable ex) {
// Typically ClassNotFoundException or NoClassDefFoundError...
return false;
}
}
}

设置初始化器

SpringApplication详细构造方法中的代码片段

setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));

设置初始化器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class SpringApplication {
...
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
return getSpringFactoriesInstances(type, new Class<?>[] {});
}
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;
}
}

Load the fully qualified class names of factory implementations of the given type from “META-INF/spring.factories”, using the given class loader.

使用给定的类装入器从“META-INF/spring.factories”加载给定类型的工厂实现的完全限定类名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public final class SpringFactoriesLoader {
...
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
MultiValueMap<String, String> result = cache.get(classLoader);
if (result != null) {
return result;
}
try {
Enumeration<URL> urls = (classLoader != null ?
classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
result = new LinkedMultiValueMap<>();
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryClassName = ((String) entry.getKey()).trim();
for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) {
result.add(factoryClassName, factoryName.trim());
}
}
}
cache.put(classLoader, result);
return result;
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
}
}

结果类型:

1
2
public interface MultiValueMap<K, V> extends Map<K, List<V>> {
}
1
jar:file:/C:/Users/boblw/.gradle/caches/modules-2/files-2.1/org.springframework.boot/spring-boot-autoconfigure/2.1.3.RELEASE/58e07f69638a3ca13dffe8a2b68d284af376d105/spring-boot-autoconfigure-2.1.3.RELEASE.jar!/META-INF/spring.factories

其中一个jar包中的spring.factories文件内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
# Auto Configuration Import Listeners
org.springframework.boot.autoconfigure.AutoConfigurationImportListener=\
org.springframework.boot.autoconfigure.condition.ConditionEvaluationReportAutoConfigurationImportListener
# Auto Configuration Import Filters
org.springframework.boot.autoconfigure.AutoConfigurationImportFilter=\
org.springframework.boot.autoconfigure.condition.OnBeanCondition,\
...
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
...
# Failure analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.autoconfigure.diagnostics.analyzer.NoSuchBeanDefinitionFailureAnalyzer,\
...
# Template availability providers
org.springframework.boot.autoconfigure.template.TemplateAvailabilityProvider=\
org.springframework.boot.autoconfigure.freemarker.FreeMarkerTemplateAvailabilityProvider,\
...

和结果类型对应起来大家就懂了吧,它会将所有jar包里的spring.factories文件内容加载合并后并缓存起来。以后通过传入class name获取到实现类并初始化。

SpringApplication详细构造方法中的代码片段
this.mainApplicationClass = deduceMainApplicationClass();
从classpath中来推断出web应用类型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;
}
...
}

ConfigurableApplicationContext

run 方法返回结果 ConfigurableApplicationContext

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable

SPI interface to be implemented by most if not all application contexts. Provides facilities to configure an application context in addition to the application context client methods in the ApplicationContext interface.

大多数应用程序上下文(如果不是全部的话)将实现SPI接口。除了ApplicationContext接口中的应用程序上下文客户端方法外,还提供配置应用程序上下文的工具。

Configuration and lifecycle methods are encapsulated here to avoid making them obvious to ApplicationContext client code. The present methods should only be used by startup and shutdown code.

这里封装了配置和生命周期方法,以避免它们被ApplicationContext公开给客户端代码。目前的方法只能在启动和关闭代码中使用。

ApplicationContextInitializer

Callback interface for initializing a Spring ConfigurableApplicationContext prior to being refreshed.

回调接口,用于Spring ConfigurableApplicationContext在刷新之前初始化它。

Typically used within web applications that require some programmatic initialization of the application context. For example, registering property sources or activating profiles against the context’s environment.

通常用于web应用程序中需要对应用程序上下文进行一些可编程的初始化。例如,注册属性源或根据上下文环境激活profiles。

SpringFactoriesLoader

General purpose factory loading mechanism for internal use within the framework.

通用的工厂加载机制在框架内部使用。

SpringFactoriesLoader loads and instantiates factories of a given type from “META-INF/spring.factories” files which may be present in multiple JAR files in the classpath. The spring.factories file must be in Properties format, where the key is the fully qualified name of the interface or abstract class, and the value is a comma-separated list of implementation class names. For example:
example.MyService=example.MyServiceImpl1,example.MyServiceImpl2
where example.MyService is the name of the interface, and MyServiceImpl1 and MyServiceImpl2 are two implementations.

SpringFactoriesLoader从“META-INF/spring.factories”中加载并实例化给定类型的工厂。spring.factories存在于类路径中的多个JAR文件中。spring.factories必须采用Properties文件格式,其中key是接口或抽象类的完全限定名,值是用逗号分隔的实现类名列表。例如:
example.MyService = example.MyServiceImpl1 example.MyServiceImpl2
example.MyService是接口的名称,MyServiceImpl1和MyServiceImpl2是两个实现。

1
2
3
4
5
6
7
8
9
10
public final class SpringFactoriesLoader {
...
public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
String factoryClassName = factoryClass.getName();
return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
}
...
}

Load the fully qualified class names of factory implementations of the given type from “META-INF/spring.factories”, using the given class loader.

ApplicationListener

Interface to be implemented by application event listeners. Based on the standard java.util.EventListener interface for the Observer design pattern.

由应用程序事件侦听器实现的接口。基于标准java.util.EventListener。观察者设计模式的接口。

As of Spring 3.0, an ApplicationListener can generically declare the event type that it is interested in. When registered with a Spring ApplicationContext, events will be filtered accordingly, with the listener getting invoked for matching event objects only.

从Spring 3.0开始,ApplicationListener通常可以声明它感兴趣的事件类型。当注册到一个Spring ApplicationContext时,事件将被相应地过滤,同时监听器仅会对所匹配的事件对象进行调用。

deduceMainApplicationClass

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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;
}
...
}

直接生成了一个运行期异常,获取到异常的堆栈信息,根据main方法所在的那个类。

run方法

Run the Spring application, creating and refreshing a new ApplicationContext.

运行一个spring应用,创建并且刷新一个新的ApplicationContext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class SpringApplication {
...
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 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;
}
...
}

ApplicationContext

Central interface to provide configuration for an application. This is read-only while the application is running, but may be reloaded if the implementation supports this.

为应用程序提供配置的中央接口。在应用程序运行时,这是只读的,但如果实现支持这一点,则可以重新加载。

An ApplicationContext provides:

一个ApplicationContext提供:

  • Bean factory methods for accessing application components. Inherited from ListableBeanFactory.
  • The ability to load file resources in a generic fashion. Inherited from the org.springframework.core.io.ResourceLoader interface.
  • The ability to publish events to registered listeners. Inherited from the ApplicationEventPublisher interface.
  • The ability to resolve messages, supporting internationalization. Inherited from the MessageSource interface.
  • Inheritance from a parent context. Definitions in a descendant context will always take priority. This means, for example, that a single parent context can be used by an entire web application, while each servlet has its own child context that is independent of that of any other servlet.

  • 用于访问应用程序组件的Bean工厂方法。从ListableBeanFactory继承。

  • 以通用方式加载文件资源的能力。继承自org.springframe.core.io.ResourceLoader接口。
  • 将事件发布到注册侦听器的能力。继承自ApplicationEventPublisher接口。
  • 解析消息的能力,支持国际化。继承自MessageSource接口。
  • 从父上下文继承。后代上下文中的定义总是拥有更高的优先级。例如,这意味着单个父上下文可以被整个web应用程序使用,而每个servlet都有自己独立于任何其他servlet的子上下文。

EventPublishingRunListener

根据SpringApplicationRunListener,getSpringFactoriesInstances()会从缓存中拿到 EventPublishingRunListener,getSpringFactoriesInstances这个方法我们已经很熟悉了。

1
2
3
4
5
6
7
8
9
10
11
12
public class SpringApplication {
...
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
...
}

EventPublishingRunListener

SpringApplicationRunListener to publish SpringApplicationEvents.
Uses an internal ApplicationEventMulticaster for the events that are fired before the context is actually refreshed.

SpringApplicationRunListener发布SpringApplicationEvents。
使用内部ApplicationEventMulticaster,在实际刷新上下文之前触发的事件 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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();
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
@Override
public int getOrder() {
return 0;
}
@Override
public void starting() {
this.initialMulticaster.multicastEvent(
new ApplicationStartingEvent(this.application, this.args));
}
...
}

SimpleApplicationEventMulticaster

Simple implementation of the ApplicationEventMulticaster interface.

简单实现的ApplicationEventMulticaster接口。

Multicasts all events to all registered listeners, leaving it up to the listeners to ignore events that they are not interested in. Listeners will usually perform corresponding instanceof checks on the passed-in event object.

将所有事件广播给所有已注册的监听器,让监听器忽略它们不感兴趣的事件。监听器通常会对传入的事件对象执行相应的instanceof检查。

By default, all listeners are invoked in the calling thread. This allows the danger of a rogue listener blocking the entire application, but adds minimal overhead. Specify an alternative task executor to have listeners executed in different threads, for example from a thread pool.

默认情况下,所有监听器都会在调用线程中执行。存在监听器阻塞整个应用程序的危险,但成本最低。可以指定一个可选的任务执行器,以便在不同的线程中(例如从线程池中)执行监听器。

Environment

Interface representing the environment in which the current application is running. Models two key aspects of the application environment: profiles and properties. Methods related to property access are exposed via the PropertyResolver superinterface.

表示当前应用程序正在运行所在环境的接口。有两个重要组成部分或者方面:profiles和properties。与属性访问相关的方法通过PropertyResolver父接口公开。

A profile is a named, logical group of bean definitions to be registered with the container only if the given profile is active. Beans may be assigned to a profile whether defined in XML or via annotations; see the spring-beans 3.1 schema or the @Profile annotation for syntax details. The role of the Environment object with relation to profiles is in determining which profiles (if any) are currently active, and which profiles (if any) should be active by default.

profile是一种命名的,逻辑的bean定义的分组,只有在给定的profile处于活动状态时才向容器注册。可以将beans赋予给一个profile,无论是在XML中定义的还是通过注释定义的;有关语法细节,请参阅spring-beans 3.1模式或@Profile注释。与概要文件相关的环境对象的作用是确定哪些profiles(如果有的话)当前是活动的,以及哪些profiles(如果有的话)在默认情况下应该是活动的。

Properties play an important role in almost all applications, and may originate from a variety of sources: properties files, JVM system properties, system environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, Maps, and so on. The role of the environment object with relation to properties is to provide the user with a convenient service interface for configuring property sources and resolving properties from them.

属性在几乎所有的应用程序中都扮演着重要的角色,它们可能来自各种各样的来源:属性文件、JVM系统属性、系统环境变量、JNDI、servlet上下文参数、特定属性对象、映射等等。与属性相关的环境对象的作用是为用户提供一个方便的服务接口,用于配置属性源并从中解析属性。

Beans managed within an ApplicationContext may register to be EnvironmentAware or @Inject the Environment in order to query profile state or resolve properties directly.
In most cases, however, application-level beans should not need to interact with the Environment directly but instead may have to have ${…} property values replaced by a property placeholder configurer such as PropertySourcesPlaceholderConfigurer, which itself is EnvironmentAware and as of Spring 3.1 is registered by default when using

1
<context:property-placeholder/>

在ApplicationContext中管理的bean可以注册为environmental aware或@Inject环境,以便直接查询profile状态或解析属性。

但是,在大多数情况下,应用程序级bean不需要直接与环境交互,而是必须使用${…}属性值被属性占位符(如PropertySourcesPlaceholderConfigurer)替换,属性占位符本身是环境敏感的,从Spring 3.1开始,在使用时默认注册

Configuration of the environment object must be done through the ConfigurableEnvironment interface, returned from all AbstractApplicationContext subclass getEnvironment() methods.

环境对象的配置必须通过ConfigurableEnvironment接口完成,该接口由所有AbstractApplicationContext子类getEnvironment()方法返回。

ConfigurableEnvironment

Configuration interface to be implemented by most if not all Environment types. Provides facilities for setting active and default profiles and manipulating underlying property sources. Allows clients to set and validate required properties, customize the conversion service and more through the ConfigurablePropertyResolver superinterface.

配置接口如果不是所有也是将由大多数环境类型实现。提供基础设施用于设置活动的和默认的profile并且可以操作底层的属性源。允许客户端通过ConfigurablePropertyResolver超接口设置和验证所需的属性、定制转换服务等。

Manipulating property sources

操纵属性源

Property sources may be removed, reordered, or replaced; and additional property sources may be added using the MutablePropertySources instance returned from getPropertySources(). The following examples are against the StandardEnvironment implementation of ConfigurableEnvironment, but are generally applicable to any implementation, though particular default property sources may differ.

属性源可以被删除、重新排序或替换;可以使用从getPropertySources()返回的MutablePropertySources实例添加其他属性源。下面的例子是针对ConfigurableEnvironment的标准环境实现的,但是通常适用于任何实现,尽管特定的默认属性源可能不同。

Example: adding a new property source with highest search priority

示例:添加具有最高搜索优先级的新属性源

1
2
3
4
5
ConfigurableEnvironment environment = new StandardEnvironment();
MutablePropertySources propertySources = environment.getPropertySources();
Map<String, String> myMap = new HashMap<>();
myMap.put("xyz", "myValue");
propertySources.addFirst(new MapPropertySource("MY_MAP", myMap));

Example: removing the default system properties property source

示例:删除默认的系统属性属性源

1
2
MutablePropertySources propertySources = environment.getPropertySources();
propertySources.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)

Example: mocking the system environment for testing purposes

示例:出于测试目的模拟系统环境

1
2
3
MutablePropertySources propertySources = environment.getPropertySources();
MockPropertySource mockEnvVars = new MockPropertySource().withProperty("xyz", "myValue");
propertySources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, mockEnvVars);

When an Environment is being used by an ApplicationContext, it is important that any such PropertySource manipulations be performed before the context’s refresh() method is called. This ensures that all property sources are available during the container bootstrap process, including use by property placeholder configurers.

当环境被ApplicationContext使用时,在调用上下文的refresh()方法之前执行任何这样的PropertySource操作是很重要的。这确保了在容器引导过程中所有的属性源都是可用的,包括属性占位符配置器的使用。

createApplicationContext

context = createApplicationContext();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class SpringApplication {
...
/**
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
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);
}
...
}