个人觉得这个也很重要的,顺便在这里参考“芋艿“的博客深入学习下底层源码,然后再配合一张图来帮助理解记忆。咱们的Spring Boot版本是1.5.9,所以您的版本里源码实现可能会有区别,但我觉得不同版本的Spring Boot整体思想应该差不多。
构造器
// sources数组仅仅包含一个元素: DemoApplication.class
public SpringApplication(Object... sources) {
initialize(sources);
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
// 判断是否是web环境,不同的spring boot版本,实现可能不一样
this.webEnvironment = deduceWebEnvironment();
// 设置ApplicationContextInitializer
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
// ApplicationListener List
setListeners((Collection)
getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
public void setInitializers(
Collection<? extends ApplicationContextInitializer<?>> initializers) {
this.initializers = new ArrayList<ApplicationContextInitializer<?>>();
this.initializers.addAll(initializers);
}
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {
this.listeners = new ArrayList<ApplicationListener<?>>();
this.listeners.addAll(listeners);
}
// 下面是SpringApplication 类的一些属性
private ConfigurableEnvironment environment;
private Class<? extends ConfigurableApplicationContext> applicationContextClass;
private boolean webEnvironment;
private List<ApplicationContextInitializer<?>> initializers;
private List<ApplicationListener<?>> listeners;
复制代码
![](liutianruo-2019-go-go-go.oss-cn-shanghai.aliyuncs.com/notes/02_Sp… Application构造器.png)
run()
这就是启动Spring Boot最核心的代码了,正菜来了哦。
public ConfigurableApplicationContext run(String... args) {
// 用来配合日志统计启动时间的
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
// awt相关,可忽略
configureHeadlessProperty();
// 获得 SpringApplicationRunListeners(封装了多个SpringApplicationRunListener)
SpringApplicationRunListeners listeners = getRunListeners(args);
// 启动监听
listeners.starting();
try {
//创建 ApplicationArguments 对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
// 加载属性配置。执行完成后,所有的 environment 的属性都会加载进来,包括 application.properties 和外部的属性配置
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
// 不重要,就控制台显示 Spring Boot 图案的,吉祥物属于是
Banner printedBanner = printBanner(environment);
// Spring上下文
context = createApplicationContext();
// 异常报告器
analyzers = new FailureAnalyzers(context);
// 调用所有初始化类的 initialize
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
// 初始化spring上下文
refreshContext(context);
//执行 Spring 上下文的初始化的后置逻辑
afterRefresh(context, applicationArguments);
// 通知***,spring上下文启动完成
listeners.finished(context, null);
// 统计时长结束
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}
复制代码
SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };
return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(
SpringApplicationRunListener.class, types, this, args));
}
复制代码
getSpringFactoriesInstances
private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
Class<?>[] parameterTypes, Object... args) {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
// Use names and ensure unique to protect against duplicates
Set<String> names = new LinkedHashSet<String>(
SpringFactoriesLoader.loadFactoryNames(type, classLoader));
List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
classLoader, args, names);
AnnotationAwareOrderComparator.sort(instances);
return instances;
}
复制代码
SpringFactoriesLoader获取META-INF/spring.factories配置的SpringApplicationRunListener实现类对应的全类名,这里会用Set来去重。
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
复制代码
SpringApplicationRunListeners(Log log,
Collection<? extends SpringApplicationRunListener> listeners) {
this.log = log;
this.listeners = new ArrayList<SpringApplicationRunListener>(listeners);
}
复制代码
拿到了SpringApplicationRunListener
实现类后,就被SpringApplicationRunListeners
作为一个List封装了起来。
EventPublishingRunListener
本质就是一个事件广播器,只是封装了一下而已,最后去处理事件的还是
ApplicationListener
。只能说EventPublishingRunListener
只是一个花钱找别人写代码的码农罢了,好吧,那SpringApplicationRunListeners
就是公司老板了。哈哈
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();
// 获取SpringApplication构造器里封装的ApplicationListener List,
// 并将List注入给impleApplicationEventMulticaster
for (ApplicationListener<?> listener : application.getListeners()) {
this.initialMulticaster.addApplicationListener(listener);
}
}
复制代码
SimpleApplicationEventMulticaster
才是底层的事件监听打工仔,可真能藏,小伙计。
看一下EvenPublishingRunListener
关于事件的处理吧。
@Override
@SuppressWarnings("deprecation")
public void starting() {
//直接广播事件去了
this.initialMulticaster
.multicastEvent(new ApplicationStartedEvent(this.application, this.args));
}
@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent(
this.application, this.args, environment));
}
复制代码
我们来验证下吧
SpringApplicationRunListeners#starting
public void starting() {
// 目前仅有一个内部实现EventPublishingRunListener
for (SpringApplicationRunListener listener : this.listeners) {
listener.starting();
}
}
复制代码
-
SpringApplicationRunListeners.starting
-
SpringApplicationRunListener.starting
EventPublishingRunListener
SimpleApplicationEventMulticaster.multicastEvent
List<ApplicationListener>
@Override public void multicastEvent(final ApplicationEvent event, ResolvableType eventType) { ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event)); for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) { Executor executor = getTaskExecutor(); if (executor != null) { executor.execute(new Runnable() { @Override public void run() { invokeListener(listener, event); } }); } else { invokeListener(listener, event); } } } 复制代码
-
留一张图吧:
至此,***(实际是广播器,最惨的是ApplicationListener了,封装了那么多层,结果还是我来处理,妈的)的内裤,我们是扒的差不多了。
ConfigurableEnvironment
private ConfigurableEnvironment prepareEnvironment(
SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments) {
// Create and configure the environment
ConfigurableEnvironment environment = getOrCreateEnvironment();
configureEnvironment(environment, applicationArguments.getSourceArgs());
listeners.environmentPrepared(environment);
if (!this.webEnvironment) {
environment = new EnvironmentConverter(getClassLoader())
.convertToStandardEnvironmentIfNecessary(environment);
}
return environment;
}
复制代码
getOrCreateEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
}
// 如果是Web环境,就创建StandardServletEnvironment
if (this.webEnvironment) {
return new StandardServletEnvironment();
}
return new StandardEnvironment();
}
复制代码
注意:我们的Spring Boot版本只有1.5,底层的Spring Framework版本是4.3,因此没有WebFlux(Since 5.0),所以就没有
StandardReactiveWebEnvironment
configureEnvironment
protected void configureEnvironment(ConfigurableEnvironment environment,
String[] args) {
configurePropertySources(environment, args);
configureProfiles(environment, args);
}
复制代码
configurePropertySources
MutablePropertySources
protected void configurePropertySources(ConfigurableEnvironment environment,
String[] args) {
MutablePropertySources sources = environment.getPropertySources();
// 配置defaultProperties
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(
name + "-" + args.hashCode(), args));
composite.addPropertySource(source);
sources.replace(name, composite);
}
else {
// 不存在,就进行添加
sources.addFirst(new SimpleCommandLinePropertySource(args));
}
}
}
复制代码
private boolean addCommandLineProperties = true;
是否添加JVM启动参数,默认是添加
configureProfiles
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<String>(this.additionalProfiles);
profiles.addAll(Arrays.asList(environment.getActiveProfiles()));
environment.setActiveProfiles(profiles.toArray(new String[profiles.size()]));
}
复制代码
再给一张图
![](liutianruo-2019-go-go-go.oss-cn-shanghai.aliyuncs.com/notes/02_Sp… Application Environment.png)
createApplicationContext
/**
* The class name of application context that will be used by default for web
* environments.
*/
public static final String DEFAULT_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext";
private static final String[] WEB_ENVIRONMENT_CLASSES = { "javax.servlet.Servlet",
"org.springframework.web.context.ConfigurableWebApplicationContext" };
protected ConfigurableApplicationContext createApplicationContext() {
Class<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
// 根据反射获取Class对象
contextClass = Class.forName(this.webEnvironment
? DEFAULT_WEB_CONTEXT_CLASS : DEFAULT_CONTEXT_CLASS);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException(
"Unable create a default ApplicationContext, "
+ "please specify an ApplicationContextClass",
ex);
}
}
//根据Class对象实例化ConfigurableApplicationContext对象
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}
复制代码
prepareContext
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
// ApplicationContext关联Environment
context.setEnvironment(environment);
// 设置 context 的一些属性
postProcessApplicationContext(context);
// 初始化 ApplicationContextInitializer
applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
logStartupInfo(context.getParent() == null);
logStartupProfileInfo(context);
}
// Add boot specific singleton beans 设置 beanFactory 的属性
context.getBeanFactory().registerSingleton("springApplicationArguments",
applicationArguments);
if (printedBanner != null) {
context.getBeanFactory().registerSingleton("springBootBanner", printedBanner);
}
// Load the sources
// 加载 BeanDefinition
Set<Object> sources = getSources();
Assert.notEmpty(sources, "Sources must not be empty");
load(context, sources.toArray(new Object[sources.size()]));
listeners.contextLoaded(context);
}
复制代码
setEnvironment
设置ApplicationContext
的Environment
属性。
postProcessApplicationContext
设置ApplicationContext
的一些属性
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());
}
}
}
复制代码
applyInitializers
protected void applyInitializers(ConfigurableApplicationContext context) {
for (ApplicationContextInitializer initializer : getInitializers()) {
// 校验 ApplicationContextInitializer 的泛型非空
Class<?> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
// ApplicationContextInitializer执行初始化逻辑
initializer.initialize(context);
}
}
复制代码
getInitializers
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
复制代码
在SpringApplication
的构造器实现中,初始化了ApplicationContextInitializer
,怎么初始化的,从META-INF/spring.factories中遍历属性为org.springframework.context.ApplicationContextInitializer
对应的属性值。
refreshContext
启动Spring容器
private void refreshContext(ConfigurableApplicationContext context) {
refresh(context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
}
catch (AccessControlException ex) {
// Not allowed in some environments.
}
}
}
protected void refresh(ApplicationContext applicationContext) {
Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);
((AbstractApplicationContext) applicationContext).refresh();
}
复制代码
org.springframework.context.support.AbstractApplicationContext#refresh
看到了吧,Spring Boot只是封装了API而已,对于Environment
做了自定义创建、还设置了ApplicationContext
的一些属性、回调ApplicationContextInitializer
实现,最后启动容器还是要借助Spring Framework中的AbstractApplicationContext.refresh
来完成。
包括事件监听也是的,最后实际去监听的ApplicationListener
也是来自于Spring Framework,所以扒皮Spring Boot源码,扒到后面,就是Spring Framework本身了。
afterRefresh
callRunners
private void callRunners(ApplicationContext context, ApplicationArguments args) {
List<Object> runners = new ArrayList<Object>();
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
for (Object runner : new LinkedHashSet<Object>(runners)) {
if (runner instanceof ApplicationRunner) {
callRunner((ApplicationRunner) runner, args);
}
if (runner instanceof CommandLineRunner) {
callRunner((CommandLineRunner) runner, args);
}
}
}
复制代码
ApplicationRunner
CommandLineRunner
这两个接口执行回调方法
一张图总结
![](liutianruo-2019-go-go-go.oss-cn-shanghai.aliyuncs.com/notes/02_Sp… Application完整.png)
作者:刘天若
链接:https://juejin.cn/post/7042483096444370958
如果你觉得本文对你有帮助,麻烦转发加关注