spring boot启动流程
大约 29 分钟
spring boot启动流程
省流
- 创建引导上下文。引导上下文的作用就是在应用上下文创建之前,可以在“启动时”和“Environment的后处理期间”获取到它,直到ApplicationContext准备好后它就不可用了。这个上下文的可以用于为创建成本高昂的单例,或需要在容器初始化之前使用的单例,提供延迟访问的机制。
- 获取spring应用程序运行监听器。这个监听器可以在springboot启动过程中发布一些事件,比如:启动时、环境的后置处理。
- 构造环境对象。首先会把命令行参数搞里面,然后会通过环境的后置处理器加载配置。
- 创建应用程序上下文。这时会把应用程序上下文配置好,同时关闭引导上下文。
- 刷新应用程序上下文。
- 回调runners接口。
- 发布应用就绪事件。
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
/**
* 构造 DefaultBootstrapContext,会使用 BootstrapRegistryInitializer 对其初始化
*
* 是在构造器收集好有哪些 BootstrapRegistryInitializer
* {@link SpringApplication#SpringApplication(ResourceLoader, Class[])}
*
* DefaultBootstrapContext 的生命周期范围是 IOC容器refresh之前
* */
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
ConfigurableApplicationContext context = null;
// 设置一个系统属性
configureHeadlessProperty();
/**
* SpringApplicationRunListeners 是 SpringApplicationRunListener 的注册器,具体干活的是 SpringApplicationRunListener
* 而具体有哪些 SpringApplicationRunListener 是读取 META-INF/spring.factories 中key为 SpringApplicationRunListener.class.getName() 的信息
*
* tips:这就是观察者模式
* */
SpringApplicationRunListeners listeners = getRunListeners(args);
// 回调 SpringApplicationRunListener#starting 方法,可以在这个方法装饰 bootstrapContext
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
// 装饰一下 args
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
/**
* 构造出 ConfigurableEnvironment
*
* 1. 可以使用 ApplicationContextFactory 来生成 ConfigurableEnvironment
* 2. 回调 SpringApplicationRunListener#environmentPrepared 配置 ConfigurableEnvironment
* 3. 修改属性的访问顺序为: 命令行参数 -> 系统属性 -> 环境变量 ... -> 默认属性(默认是空的)
* */
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
// 设置一个名叫 spring.beaninfo.ignore 的系统属性
configureIgnoreBeanInfo(environment);
/**
* 构造出 Banner 并打印出banner的内容
* 会尝试从 environment 获取属性指定的文件
* spring.banner.image.location
* spring.banner.location
* 或者是 banner.[jpg | gif | png | txt]对应的文件
* 作为要输出的内容
* */
Banner printedBanner = printBanner(environment);
/**
* 会根据环境推断出应该创建什么类型的IOC容器:
* - AnnotationConfigApplicationContext
* - AnnotationConfigServletWebServerApplicationContext
* - ApplicationReactiveWebEnvironment
*
* 会回调 {@link ApplicationContextFactory#create(WebApplicationType)} 方法构造出 context
* */
context = createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
/**
* 配置 IOC 容器:
* 1. 给IOC容器设置上 environment
* 2. 给IOC容器设置上 ResourceLoader、ConversionService
* 3. 回调 ApplicationContextInitializer、SpringApplicationRunListener、bootstrapContext 方法
* 3.1 初始化IOC容器 ApplicationContextInitializer#initialize
* 3.2 配置IOC容器 SpringApplicationRunListener#contextPrepared
* 3.3 完成DefaultBootstrapContext的生命周期 DefaultBootstrapContext#close
* 3.4 IOC容器配置好了 SpringApplicationRunListener#contextLoaded
*
* 4. 添加单例bean:springApplicationArguments、springBootBanner
* 5. 设置两个属性 allowCircularReferences、allowBeanDefinitionOverriding
* 6. 添加两个BeanFactoryPostProcessor:
* LazyInitializationBeanFactoryPostProcessor:这个是用来判断是否需要给补全信息的 `beanDefinition.setLazyInit(true);`
* PropertySourceOrderingBeanFactoryPostProcessor:这个是用来将名叫 defaultProperties 的 PropertySource 移到 最后面的,也就是属性访问的优先级最低
* 7. 将启动类添加到IOC容器中,说白了就是注册配置类
* */
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
// 刷新IOC容器
refreshContext(context);
// 预留的模板方法
afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
}
/**
* 回调 SpringApplicationRunListener#started 方法(IOC容器启动耗时)
* {@link SpringApplicationRunListener#started(ConfigurableApplicationContext, Duration)}
* */
listeners.started(context, timeTakenToStartup);
// 回调 容器中类型是 ApplicationRunner、CommandLineRunner 的bean的方法
callRunners(context, applicationArguments);
} catch (Throwable ex) {
/**
* 处理异常情况:
* 1. 使用 context 发布 ExitCodeEvent 事件
* 2. 回调 SpringApplicationRunListener#failed 方法
* */
handleRunFailure(context, ex, listeners);
throw new IllegalStateException(ex);
}
try {
// 启动耗时
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
/**
* 回调 SpringApplicationRunListener#ready 方法(SpringBoot启动耗时)
* {@link SpringApplicationRunListener#ready(ConfigurableApplicationContext, Duration)}
* */
listeners.ready(context, timeTakenToReady);
} catch (Throwable ex) {
handleRunFailure(context, ex, null);
throw new IllegalStateException(ex);
}
// 返回IOC容器
return context;
}
创建引导上下文
DefaultBootstrapContext 作为 BootstrapContext 接口的默认实现,主要用于在 Spring Boot 应用启动的各个阶段中发布不同类型的事件。在 Spring Boot 启动过程中,会逐步加载配置和组件,并在各个阶段发布相应的事件。开发人员可以通过监听这些事件,来进行特定的初始化或程序逻辑操作。
DefaultBootstrapContext bootstrapContext = createBootstrapContext();
SpringApplication:
private DefaultBootstrapContext createBootstrapContext() {
// 创建引导上下文
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
// 初始化器初始化引导上下文
this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
// 返回创建的引导上下文
return bootstrapContext;
}
/**
* 一个 {@link BootstrapContext},它还通过
* {@link BootstrapRegistry} 接口。
*
* @author Phillip Webb
* @see BootstrapRegistry
* @see BootstrapContext
* @see DefaultBootstrapContext
* @since 2.4.0
*/
public interface ConfigurableBootstrapContext extends BootstrapRegistry, BootstrapContext {
}
/**
* 在启动期间可用的简单对象注册表和 {@link Environment}
* 后处理,直到 {@link ApplicationContext} 准备好为止。
* <p>
* 可用于注册创建成本高昂或需要共享的实例
* 之前 {@link ApplicationContext} 可用。
* <p>
* 注册表使用 {@link Class} 作为键,这意味着只有
* 可以存储给定的类型。
* <p>
* {@link #addCloseListener(ApplicationListener)} 方法可用于添加监听器
* 可以在 {@link BootstrapContext} 关闭且
* {@link ApplicationContext} 已做好充分准备。例如,实例可以选择
* 将自己注册为常规的 Spring bean,以便它可供应用程序使用
* 用。
*
* @author Phillip Webb
* @see BootstrapContext
* @see ConfigurableBootstrapContext
* @since 2.4.0
*/
public interface BootstrapRegistry {
/**
* 向注册表注册特定类型。如果指定的类型已经
* 已注册且尚未作为 {@link Scope#SINGLETON 单例}获得,它
* 将被替换。
*
* @param <T> the instance type
* @param type the instance type
* @param instanceSupplier the instance supplier
*/
<T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier);
/**
* 如果尚未向注册表注册特定类型,请向注册表注册该类型。
*
* @param <T> the instance type
* @param type the instance type
* @param instanceSupplier the instance supplier
*/
<T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier);
/**
* 如果给定类型存在注册,则返回。
*
* @param <T> the instance type
* @param type the instance type
* @return {@code true} if the type has already been registered
*/
<T> boolean isRegistered(Class<T> type);
/**
* 返回给定类型的任何现有 {@link InstanceSupplier}。
*
* @param <T> the instance type
* @param type the instance type
* @return the registered {@link InstanceSupplier} or {@code null}
*/
<T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type);
/**
* 添加一个 {@link ApplicationListener},它将使用
* {@link BootstrapContextClosedEvent} 当 {@link BootstrapContext} 关闭且
* {@link ApplicationContext} 已准备好。
*
* @param listener the listener to add
*/
void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener);
/**
* Supplier used to provide the actual instance when needed.
*
* @param <T> the instance type
* @see Scope
*/
@FunctionalInterface
interface InstanceSupplier<T> {
/**
* Factory method used to create the instance when needed.
*
* @param context the {@link BootstrapContext} which may be used to obtain other
* bootstrap instances.
* @return the instance
*/
T get(BootstrapContext context);
/**
* Return the scope of the supplied instance.
*
* @return the scope
* @since 2.4.2
*/
default Scope getScope() {
return Scope.SINGLETON;
}
/**
* Return a new {@link InstanceSupplier} with an updated {@link Scope}.
*
* @param scope the new scope
* @return a new {@link InstanceSupplier} instance with the new scope
* @since 2.4.2
*/
default InstanceSupplier<T> withScope(Scope scope) {
Assert.notNull(scope, "Scope must not be null");
InstanceSupplier<T> parent = this;
return new InstanceSupplier<T>() {
@Override
public T get(BootstrapContext context) {
return parent.get(context);
}
@Override
public Scope getScope() {
return scope;
}
};
}
/**
* Factory method that can be used to create an {@link InstanceSupplier} for a
* given instance.
*
* @param <T> the instance type
* @param instance the instance
* @return a new {@link InstanceSupplier}
*/
static <T> InstanceSupplier<T> of(T instance) {
return (registry) -> instance;
}
/**
* Factory method that can be used to create an {@link InstanceSupplier} from a
* {@link Supplier}.
*
* @param <T> the instance type
* @param supplier the supplier that will provide the instance
* @return a new {@link InstanceSupplier}
*/
static <T> InstanceSupplier<T> from(Supplier<T> supplier) {
return (registry) -> (supplier != null) ? supplier.get() : null;
}
}
/**
* The scope of an instance.
*
* @since 2.4.2
*/
enum Scope {
/**
* A singleton instance. The {@link InstanceSupplier} will be called only once and
* the same instance will be returned each time.
*/
SINGLETON,
/**
* A prototype instance. The {@link InstanceSupplier} will be called whenever an
* instance is needed.
*/
PROTOTYPE
}
}
/**
* 在启动期间可用的简单引导上下文和 {@link Environment}
* 后处理,直到 {@link ApplicationContext} 准备好为止。
* <p>
* 提供对创建成本可能很高或需要的单例的延迟访问
* 在 {@link ApplicationContext} 可用之前共享。
*
* @author Phillip Webb
* @since 2.4.0
*/
public interface BootstrapContext {
/**
* 如果类型已注册,则从上下文中返回实例。实例
* 如果以前未访问过,则将创建它。
*
* @param <T> the instance type
* @param type the instance type
* @return the instance managed by the context
* @throws IllegalStateException if the type has not been registered
*/
<T> T get(Class<T> type) throws IllegalStateException;
/**
* 如果类型已注册,则从上下文中返回实例。实例
* 如果以前未访问过,则将创建它。
*
* @param <T> the instance type
* @param type the instance type
* @param other the instance to use if the type has not been registered
* @return the instance
*/
<T> T getOrElse(Class<T> type, T other);
/**
* 如果类型已注册,则从上下文中返回实例。实例
* 如果以前未访问过,则将创建它。
*
* @param <T> the instance type
* @param type the instance type
* @param other a supplier for the instance to use if the type has not been registered
* @return the instance
*/
<T> T getOrElseSupply(Class<T> type, Supplier<T> other);
/**
* 如果类型已注册,则从上下文中返回实例。实例
* 如果以前未访问过,则将创建它。
*
* @param <T> the instance type
* @param <X> the exception to throw if the type is not registered
* @param type the instance type
* @param exceptionSupplier the supplier which will return the exception to be thrown
* @return the instance managed by the context
* @throws X if the type has not been registered
* @throws IllegalStateException if the type has not been registered
*/
<T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X;
/**
* 如果给定类型存在注册,则返回。
*
* @param <T> the instance type
* @param type the instance type
* @return {@code true} if the type has already been registered
*/
<T> boolean isRegistered(Class<T> type);
}
/**
* Default {@link ConfigurableBootstrapContext} implementation.
*
* @author Phillip Webb
* @since 2.4.0
*/
public class DefaultBootstrapContext implements ConfigurableBootstrapContext {
private final Map<Class<?>, InstanceSupplier<?>> instanceSuppliers = new HashMap<>();
private final Map<Class<?>, Object> instances = new HashMap<>();
private final ApplicationEventMulticaster events = new SimpleApplicationEventMulticaster();
@Override
public <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier) {
register(type, instanceSupplier, true);
}
@Override
public <T> void registerIfAbsent(Class<T> type, InstanceSupplier<T> instanceSupplier) {
register(type, instanceSupplier, false);
}
private <T> void register(Class<T> type, InstanceSupplier<T> instanceSupplier, boolean replaceExisting) {
Assert.notNull(type, "Type must not be null");
Assert.notNull(instanceSupplier, "InstanceSupplier must not be null");
synchronized (this.instanceSuppliers) {
// 已经注册
boolean alreadyRegistered = this.instanceSuppliers.containsKey(type);
// 替换或者未注册
if (replaceExisting || !alreadyRegistered) {
Assert.state(!this.instances.containsKey(type), () -> type.getName() + " has already been created");
this.instanceSuppliers.put(type, instanceSupplier);
}
}
}
@Override
public <T> boolean isRegistered(Class<T> type) {
synchronized (this.instanceSuppliers) {
return this.instanceSuppliers.containsKey(type);
}
}
@Override
@SuppressWarnings("unchecked")
public <T> InstanceSupplier<T> getRegisteredInstanceSupplier(Class<T> type) {
synchronized (this.instanceSuppliers) {
return (InstanceSupplier<T>) this.instanceSuppliers.get(type);
}
}
@Override
public void addCloseListener(ApplicationListener<BootstrapContextClosedEvent> listener) {
this.events.addApplicationListener(listener);
}
@Override
public <T> T get(Class<T> type) throws IllegalStateException {
return getOrElseThrow(type, () -> new IllegalStateException(type.getName() + " has not been registered"));
}
@Override
public <T> T getOrElse(Class<T> type, T other) {
return getOrElseSupply(type, () -> other);
}
@Override
public <T> T getOrElseSupply(Class<T> type, Supplier<T> other) {
synchronized (this.instanceSuppliers) {
InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);
return (instanceSupplier != null) ? getInstance(type, instanceSupplier) : other.get();
}
}
@Override
public <T, X extends Throwable> T getOrElseThrow(Class<T> type, Supplier<? extends X> exceptionSupplier) throws X {
synchronized (this.instanceSuppliers) {
InstanceSupplier<?> instanceSupplier = this.instanceSuppliers.get(type);
if (instanceSupplier == null) {
throw exceptionSupplier.get();
}
return getInstance(type, instanceSupplier);
}
}
@SuppressWarnings("unchecked")
private <T> T getInstance(Class<T> type, InstanceSupplier<?> instanceSupplier) {
T instance = (T) this.instances.get(type);
if (instance == null) {
instance = (T) instanceSupplier.get(this);
if (instanceSupplier.getScope() == Scope.SINGLETON) {
this.instances.put(type, instance);
}
}
return instance;
}
/**
* Method to be called when {@link BootstrapContext} is closed and the
* {@link ApplicationContext} is prepared.
* @param applicationContext the prepared context
*/
public void close(ConfigurableApplicationContext applicationContext) {
this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
}
}
其中bootstrapRegistryInitializers是在SpringApplication的构造中初始化的,通过Spring工厂加载。
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
......
// 读取 META-INF/spring.factories 中key为 BootstrapRegistryInitializer.class.getName() 的信息,然后反射实例化
/**
* 这是用来在 run 环节对 BootstrapRegistry 进行初始化的
* {@link SpringApplication#createBootstrapContext()}
* */
this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
......
}
SpringApplication:
// 从springfactores获取指定类型的实例
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();
// 读取 META-INF/spring.factories 中key为 type.getName() 的信息
// 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;
}
// 通过反射获取指定类的实例
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
ClassLoader classLoader, Object[] args, Set<String> names) {
List<T> instances = new ArrayList<>(names.size());
for (String name : names) {
try {
Class<?> instanceClass = ClassUtils.forName(name, classLoader);
Assert.isAssignable(type, instanceClass);
Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
T instance = (T) BeanUtils.instantiateClass(constructor, args);
instances.add(instance);
} catch (Throwable ex) {
throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
}
}
return instances;
}
SpringFactoriesLoader:
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
// 获取指定类型实例的全限定类名
public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
}
String factoryTypeName = factoryType.getName();
return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
}
private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
Map<String, List<String>> result = cache.get(classLoader);
if (result != null) {
return result;
}
result = new HashMap<>();
try {
Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
while (urls.hasMoreElements()) {
URL url = urls.nextElement();
UrlResource resource = new UrlResource(url);
Properties properties = PropertiesLoaderUtils.loadProperties(resource);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
String factoryTypeName = ((String) entry.getKey()).trim();
String[] factoryImplementationNames =
StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
for (String factoryImplementationName : factoryImplementationNames) {
result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>())
.add(factoryImplementationName.trim());
}
}
}
// Replace all lists with unmodifiable lists containing unique elements
result.replaceAll((factoryType, implementations) -> implementations.stream().distinct()
.collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
cache.put(classLoader, result);
}
catch (IOException ex) {
throw new IllegalArgumentException("Unable to load factories from location [" +
FACTORIES_RESOURCE_LOCATION + "]", ex);
}
return result;
}
获取Spring运行监听器
/**
* SpringApplicationRunListeners 是 SpringApplicationRunListener 的注册器,具体干活的是 SpringApplicationRunListener
* 而具体有哪些 SpringApplicationRunListener 是读取 META-INF/spring.factories 中key为 SpringApplicationRunListener.class.getName() 的信息
* */
SpringApplicationRunListeners listeners = getRunListeners(args);
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger,
getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args),
this.applicationStartup
);
}
应用启动回调
// 回调 SpringApplicationRunListener#starting 方法,可以在这个方法装饰 bootstrapContext
listeners.starting(bootstrapContext, this.mainApplicationClass);
SpringApplicationRunListeners:
void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
(step) -> {
if (mainApplicationClass != null) {
step.tag("mainApplicationClass", mainApplicationClass.getName());
}
});
}
private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
Consumer<StartupStep> stepAction) {
StartupStep step = this.applicationStartup.start(stepName);
this.listeners.forEach(listenerAction);
if (stepAction != null) {
stepAction.accept(step);
}
step.end();
}
在spring-boot-project的META-INF下默认配置:
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
@Override
public void starting(ConfigurableBootstrapContext bootstrapContext) {
this.initialMulticaster
.multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
}
创建命令行参数对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
DefaultApplicationArguments:
public DefaultApplicationArguments(String... args) {
Assert.notNull(args, "Args must not be null");
this.source = new Source(args);
this.args = args;
}
Source:
private static class Source extends SimpleCommandLinePropertySource {
Source(String[] args) {
super(args);
}
@Override
public List<String> getNonOptionArgs() {
return super.getNonOptionArgs();
}
@Override
public List<String> getOptionValues(String name) {
return super.getOptionValues(name);
}
}
public class SimpleCommandLinePropertySource extends CommandLinePropertySource<CommandLineArgs> {
/**
* Create a new {@code SimpleCommandLinePropertySource} having the default name
* and backed by the given {@code String[]} of command line arguments.
* @see CommandLinePropertySource#COMMAND_LINE_PROPERTY_SOURCE_NAME
* @see CommandLinePropertySource#CommandLinePropertySource(Object)
*/
public SimpleCommandLinePropertySource(String... args) {
super(new SimpleCommandLineArgsParser().parse(args));
}
/**
* Create a new {@code SimpleCommandLinePropertySource} having the given name
* and backed by the given {@code String[]} of command line arguments.
*/
public SimpleCommandLinePropertySource(String name, String[] args) {
super(name, new SimpleCommandLineArgsParser().parse(args));
}
/**
* Get the property names for the option arguments.
*/
@Override
public String[] getPropertyNames() {
return StringUtils.toStringArray(this.source.getOptionNames());
}
@Override
protected boolean containsOption(String name) {
return this.source.containsOption(name);
}
@Override
@Nullable
protected List<String> getOptionValues(String name) {
return this.source.getOptionValues(name);
}
@Override
protected List<String> getNonOptionArgs() {
return this.source.getNonOptionArgs();
}
}
class SimpleCommandLineArgsParser {
public CommandLineArgs parse(String... args) {
CommandLineArgs commandLineArgs = new CommandLineArgs();
for (String arg : args) {
// 可选参数
if (arg.startsWith("--")) {
String optionText = arg.substring(2);
String optionName;
String optionValue = null;
int indexOfEqualsSign = optionText.indexOf('=');
if (indexOfEqualsSign > -1) {
optionName = optionText.substring(0, indexOfEqualsSign);
optionValue = optionText.substring(indexOfEqualsSign + 1);
}
else {
optionName = optionText;
}
if (optionName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
commandLineArgs.addOptionArg(optionName, optionValue);
}
else {
// 非可选参数
commandLineArgs.addNonOptionArg(arg);
}
}
return commandLineArgs;
}
}
构造环境对象
/**
* 构造出 ConfigurableEnvironment
*
* 1. 可以使用 ApplicationContextFactory 来生成 ConfigurableEnvironment
* 2. 回调 SpringApplicationRunListener#environmentPrepared 配置 ConfigurableEnvironment
* 3. 修改属性的访问顺序为: 命令行参数 -> 系统属性 -> 环境变量 ... -> 默认属性(默认是空的)
* */
ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,
DefaultBootstrapContext bootstrapContext,
ApplicationArguments applicationArguments) {
/**
* 创建出 ConfigurableEnvironment
* 在Servlet环境下是ApplicationServletEnvironment
* */
ConfigurableEnvironment environment = getOrCreateEnvironment();
/**
* 配置Environment,其实就是扩展Environment能访问的属性信息
* 访问顺序:命令行参数 -> ... -> 默认属性
* */
configureEnvironment(environment, applicationArguments.getSourceArgs());
// 将 ConfigurationPropertySourcesPropertySource 放到第一个位置
ConfigurationPropertySources.attach(environment);
/**
* 回调 {@link SpringApplicationRunListener#environmentPrepared(ConfigurableBootstrapContext, ConfigurableEnvironment)}
* 对 environment 进行配置
* */
listeners.environmentPrepared(bootstrapContext, environment);
// 移动 defaultProperties 到最后,即优先级最低
DefaultPropertiesPropertySource.moveToEnd(environment);
Assert.state(
!environment.containsProperty("spring.main.environment-prefix"),
"Environment prefix cannot be set via properties."
);
// 将当前的 SpringApplication 实例绑定到Spring Boot应用程序的配置环境 (ConfigurableEnvironment) 中的 spring.main 属性下
bindToSpringApplication(environment);
if (!this.isCustomEnvironment) {
EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());
// 转换成 ConfigurableEnvironment 类型的
environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());
}
// 同上
ConfigurationPropertySources.attach(environment);
return environment;
}
配置环境
SpringApplication:
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
environment.setConversionService(new ApplicationConversionService());
}
/**
* 扩展 environment 访问的属性
*
* 访问顺序:命令行参数 -> ... -> 默认属性
*
* */
configurePropertySources(environment, args);
// 模板方法,空实现
configureProfiles(environment, args);
}
/**
* 在此应用程序的环境中添加、删除或重新排序任何 {@link PropertySource}。
*
* @param environment this application's environment
* @param args arguments passed to the {@code run} method
* @see #configureEnvironment(ConfigurableEnvironment, String[])
*/
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
if (!CollectionUtils.isEmpty(this.defaultProperties)) {
// 将 defaultProperties 装饰成 propertySource 然后注册到 sources 中(放在最后)
DefaultPropertiesPropertySource.addOrMerge(this.defaultProperties, sources);
}
// 将 args 构造成 SimpleCommandLinePropertySource 然后注册到 sources 中(放到前面)
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));
}
}
}
添加附加属性
ConfigurationPropertySources:
public static void attach(Environment environment) {
Assert.isInstanceOf(ConfigurableEnvironment.class, environment);
MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources();
// 拿到叫这个名字的 configurationProperties PropertySource
PropertySource<?> attached = getAttached(sources);
// 这个判断是为了防止重复下面的操作
if (attached == null || !isUsingSources(attached, sources)) {
// 装饰成 ConfigurationPropertySourcesPropertySource
attached = new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,
new SpringConfigurationPropertySources(sources));
}
sources.remove(ATTACHED_PROPERTY_SOURCE_NAME);
// 放到前面
sources.addFirst(attached);
}
❓发布环境准备事件
todo 这里是非常核心的,设计配置的加载,需要专门研究一下。
SpringApplicationRunListeners:
void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
doWithListeners("spring.boot.application.environment-prepared",
(listener) -> listener.environmentPrepared(bootstrapContext, environment));
}
EventPublishingRunListener:
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(
new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
}
创建应用程序上下文
/**
* 会根据环境推断出应该创建什么类型的IOC容器:
* - AnnotationConfigApplicationContext
* - AnnotationConfigServletWebServerApplicationContext
* - ApplicationReactiveWebEnvironment
*
* 会回调 {@link ApplicationContextFactory#create(WebApplicationType)} 方法构造出 context
* */
context = createApplicationContext();
在Servlet的环境下会创建AnnotationConfigServletWebServerApplicationContext。
配置应用程序上下文
/**
* 配置 IOC 容器:
* 1. 给IOC容器设置上 environment
* 2. 给IOC容器设置上 ResourceLoader、ConversionService
* 3. 回调 ApplicationContextInitializer、SpringApplicationRunListener、bootstrapContext 方法
* 3.1 初始化IOC容器 ApplicationContextInitializer#initialize
* 3.2 配置IOC容器 SpringApplicationRunListener#contextPrepared
* 3.3 完成DefaultBootstrapContext的生命周期 DefaultBootstrapContext#close
* 3.4 IOC容器配置好了 SpringApplicationRunListener#contextLoaded
*
* 4. 添加单例bean:springApplicationArguments、springBootBanner
* 5. 设置两个属性 allowCircularReferences、allowBeanDefinitionOverriding
* 6. 添加两个BeanFactoryPostProcessor:
* LazyInitializationBeanFactoryPostProcessor:这个是用来判断是否需要给补全信息的 `beanDefinition.setLazyInit(true);`
* PropertySourceOrderingBeanFactoryPostProcessor:这个是用来将名叫 defaultProperties 的 PropertySource 移到 最后面的,也就是属性访问的优先级最低
* 7. 将启动类添加到IOC容器中,说白了就是注册配置类
* */
prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
后置处理应用上下文
SpringApplication:
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
if (this.beanNameGenerator != null) {
context.getBeanFactory()
.registerSingleton(AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR, this.beanNameGenerator);
}
if (this.resourceLoader != null) {
if (context instanceof GenericApplicationContext) {
((GenericApplicationContext) context).setResourceLoader(this.resourceLoader);
}
if (context instanceof DefaultResourceLoader) {
((DefaultResourceLoader) context).setClassLoader(this.resourceLoader.getClassLoader());
}
}
if (this.addConversionService) {
context.getBeanFactory()
.setConversionService(context.getEnvironment()
.getConversionService());
}
}
应用初始化器
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(initializer.getClass(),
ApplicationContextInitializer.class
);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
上下文初始化回调
EventPublishingRunListener:
public void contextPrepared(ConfigurableApplicationContext context) {
this.initialMulticaster
.multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
}
引导上下文关闭
public void close(ConfigurableApplicationContext applicationContext) {
this.events.multicastEvent(new BootstrapContextClosedEvent(this, applicationContext));
}
上下文准备回调
public void contextLoaded(ConfigurableApplicationContext context) {
for (ApplicationListener<?> listener : this.application.getListeners()) {
if (listener instanceof ApplicationContextAware) {
// 设置IOC容器
((ApplicationContextAware) listener).setApplicationContext(context);
}
// 给IOC容器 添加 listener
context.addApplicationListener(listener);
}
// 发布事件
this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
}
刷新应用程序上下文
核心,在spring源码文章分析。
refreshContext(context);
应用启动事件回调
EventPublishingRunListener:
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
}
回调Runners
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());
// 排序,会按照 Ordered 或者 @Order 或者 @Priority 升序排序
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);
}
}
}
应用就绪回调
EventPublishingRunListener:
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context, timeTaken));
AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
}