- 入口类
- run方法源码解析
- 1.设置应用类型
- 2.设置初始化器
- 3.设置监听器
- SpringApplication.run方法
- 1.第一步:获取并启动监听器
- 2.环境构建
- 3.创建容器
- 4.容器前置处理
- 5.刷新容器
- 6.容器后置处理
- 7.发出结束执行的事件
- 8.执行Runners
@SpringBootApplication
public class HelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(HelloWorldApplication.class, args);
}
}
run方法源码解析
我们可以看到进入run方法后调用静态方法并声明一个SpringApplication的实例并传入参数HelloWorldApplication.class,然后运行run方法。
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);
}
首先我们先看一下SpringApplication构造方法都做了哪些操作
public SpringApplication(ResourceLoader resourceLoader, Class... primarySources) {
this.sources = new LinkedHashSet();
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true;
this.additionalProfiles = new HashSet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
1.设置应用类型
static WebApplicationType deduceFromClasspath() {
if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null) && !ClassUtils.isPresent("org.glassfish.jersey.servlet.ServletContainer", (ClassLoader)null)) {
return REACTIVE;
} else {
String[] var0 = SERVLET_INDICATOR_CLASSES;
int var1 = var0.length;
for(int var2 = 0; var2 < var1; ++var2) {
String className = var0[var2];
if (!ClassUtils.isPresent(className, (ClassLoader)null)) {
return NONE;
}
}
return SERVLET;
}
}
这里主要是通过类加载器判断REACTIVE相关的Class是否存在,如果不存在,则web环境即为SERVLET类型。
2.设置初始化器this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
我们先来看看getSpringFactoriesInstances( ApplicationContextInitializer.class)
privateCollection getSpringFactoriesInstances(Class type) { return this.getSpringFactoriesInstances(type, new Class[0]); } // 这里的入参type就是ApplicationContextInitializer.class private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); // 使用Set保存names来避免重复元素 Set names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); // 根据names来进行实例化 List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); //对实例进行排序 AnnotationAwareOrderComparator.sort(instances); return instances; }
我们看下根据入参type读取所有的name
public static ListloadFactoryNames(Class> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } private static Map > loadSpringFactories(@Nullable ClassLoader classLoader) { MultiValueMap result = (MultiValueMap)cache.get(classLoader); if (result != null) { return result; } else { try { //从类路径的META-INF/spring.factories中加载所有默认的自动配置类 Enumeration urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); while(var6.hasNext()) { Entry, ?> entry = (Entry)var6.next(); //获取ApplicationContextInitializer.class的所有值 String factoryTypeName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryImplementationName = var9[var11]; result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException var13) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); } } }
这个方法会尝试从类路径的META-INF/spring.factories处读取相应配置文件,然后进行遍历,读取配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value,比如以spring-boot-autoconfigure这个包为例,它的META-INF/spring.factories部分定义如下所示:
读取里面的两个类名,然后放到Set集合中,然后进行实例化过程。
privateList createSpringFactoriesInstances(Class type, Class>[] parameterTypes, ClassLoader classLoader, Object[] args, Set names) { List instances = new ArrayList(names.size()); Iterator var7 = names.iterator(); while(var7.hasNext()) { String name = (String)var7.next(); try { Class> instanceClass = ClassUtils.forName(name, classLoader); //确认被加载类是ApplicationContextInitializer的子类 Assert.isAssignable(type, instanceClass); Constructor> constructor = instanceClass.getDeclaredConstructor(parameterTypes); //反射实例化对象 T instance = BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable var12) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, var12); } } return instances; }
确认被加载的类确实是org.springframework.context.ApplicationContextInitializer的子类,然后就是得到构造器进行初始化,最后放入到实例列表中。
3.设置监听器this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
这里我们具体看下getSpringFactoriesInstances方法
privateCollection getSpringFactoriesInstances(Class type) { return this.getSpringFactoriesInstances(type, new Class[0]); } private Collection getSpringFactoriesInstances(Class type, Class>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); Set names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
可以发现,这个加载相应的类名,然后完成实例化的过程和上面在设置初始化器时如出一辙,至此,对于SpringApplication实例的初始化过程就结束了。
SpringApplication.run方法public ConfigurableApplicationContext run(String... args) {
//计时工具
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection exceptionReporters = new ArrayList();
this.configureHeadlessProperty();
// 第一步:获取并启动监听器
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting();
Collection exceptionReporters;
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
// 第二步:根据SpringApplicationRunListeners以及参数来准备环境
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
this.configureIgnoreBeanInfo(environment);
//准备banner打印器
Banner printedBanner = this.printBanner(environment);
// 第三步:创建Spring容器
context = this.createApplicationContext();
exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
// 第四步:Spring容器前置处理
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
// 第五步:刷新容器
this.refreshContext(context);
// 第六步:Spring容器后置处理
this.afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
}
listeners.started(context);
// 第八步:执行Runners
this.callRunners(context, applicationArguments);
} catch (Throwable var10) {
this.handleRunFailure(context, var10, exceptionReporters, listeners);
throw new IllegalStateException(var10);
}
try {
listeners.running(context);
// 返回容器
return context;
} catch (Throwable var9) {
this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var9);
}
}
- 第一步:获取并启动监听器
- 第二步:根据SpringApplicationRunListeners以及参数来准备环境
- 第三步:创建Spring容器
- 第四步:Spring容器前置处理
- 第五步:刷新容器
- 第六步:Spring容器后置处理
- 第七步:发出结束执行的事件
- 第八步:执行Runners
下面我们详细介绍一下这几个步骤究竟做了哪些事情
1.第一步:获取并启动监听器SpringApplicationRunListeners listeners = this.getRunListeners(args);
我们看下getRunListener(args)
private SpringApplicationRunListeners getRunListeners(String[] args) {
Class>[] types = new Class[]{SpringApplication.class, String[].class};
return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));
}
这里仍然利用了getSpringFactoriesInstances方法来获取实例,大家可以看看前面的这个方法分析,从META-INF/spring.factories中读取Key为org.springframework.boot.SpringApplicationRunListener的Values:
org.springframework.boot.context.event.EventPublishingRunListener。
getSpringFactoriesInstances中反射获取实例时会触发EventPublishingRunListener的构造函数,我们来看看EventPublishingRunListener的构造函数:
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();
Iterator var3 = application.getListeners().iterator();
while(var3.hasNext()) {
ApplicationListener> listener = (ApplicationListener)var3.next();
//将监听器全部加入到广播中
this.initialMulticaster.addApplicationListener(listener);
}
}
......
}
我们看到EventPublishingRunListener里面有一个广播器,EventPublishingRunListener 的构造方法将SpringApplication的十一个监听器全部添加到SimpleApplicationEventMulticaster这个广播器中。
我们看下接口SpringApplicationRunListener这个接口
public interface SpringApplicationRunListener {
// 在run()方法开始执行时,该方法就立即被调用,可用于在初始化最早期时做一些工作
void starting();
// 当environment构建完成,ApplicationContext创建之前,该方法被调用
void environmentPrepared(ConfigurableEnvironment environment);
// 当ApplicationContext构建完成时,该方法被调用
void contextPrepared(ConfigurableApplicationContext context);
// 在ApplicationContext完成加载,但没有被刷新前,该方法被调用
void contextLoaded(ConfigurableApplicationContext context);
// 在ApplicationContext刷新并启动后,CommandLineRunners和ApplicationRunner未被调用前,该方法被调用
void started(ConfigurableApplicationContext context);
// 在run()方法执行完成前该方法被调用
void running(ConfigurableApplicationContext context);
// 当应用运行出错时该方法被调用
void failed(ConfigurableApplicationContext context, Throwable exception);
}
SpringApplicationRunListener接口在Spring Boot 启动初始化的过程中各种状态时执行,我们也可以添加自己的监听器,在SpringBoot初始化时监听事件执行自定义逻辑,我们先来看看SpringBoot启动时第一个启动事件listeners.starting():
public void starting() {
//关键代码,先创建application启动事件`ApplicationStartingEvent`
this.initialMulticaster.multicastEvent(new ApplicationStartingEvent(this.application, this.args));
}
这里先创建了一个启动事件ApplicationStartingEvent,在multicastEvent中:
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
Executor executor = this.getTaskExecutor();
//通过事件类型ApplicationStartingEvent获取对应的监听器
Iterator var5 = this.getApplicationListeners(event, type).iterator();
while(var5.hasNext()) {
ApplicationListener> listener = (ApplicationListener)var5.next();
if (executor != null) {
executor.execute(() -> {
//异步发送事件
this.invokeListener(listener, event);
});
} else {
//同步发送事件
this.invokeListener(listener, event);
}
}
}
因为我们的事件类型为ApplicationEvent,所以会执行onApplicationStartedEvent((ApplicationStartedEvent) event);。springBoot会在运行过程中的不同阶段,发送各种事件,来执行对应监听器的对应方法
2.环境构建ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
我们看下prepareEnvironment
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {
//获取对应的ConfigurableEnvironment
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
//配置
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
ConfigurationPropertySources.attach((Environment)environment);
//发布环境已准备事件,这是第二次发布事件
listeners.environmentPrepared((ConfigurableEnvironment)environment);
this.bindToSpringApplication((ConfigurableEnvironment)environment);
if (!this.isCustomEnvironment) {
environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
}
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
来看一下getOrCreateEnvironment()方法,前面已经提到,environment已经被设置了servlet类型,所以这里创建的是环境对象是StandardServletEnvironment。
private ConfigurableEnvironment getOrCreateEnvironment() {
if (this.environment != null) {
return this.environment;
} else {
switch(this.webApplicationType) {
case SERVLET:
return new StandardServletEnvironment();
case REACTIVE:
return new StandardReactiveWebEnvironment();
default:
return new StandardEnvironment();
}
}
}
接下来看下第二次发布事件listeners.environmentPrepared(environment),首先还是会去读spring.factories 文件,执行完监听器流程然后会执行监听器类本身的逻辑。
3.创建容器context = this.createApplicationContext();
protected ConfigurableApplicationContext createApplicationContext() {
Class> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
switch(this.webApplicationType) {
case SERVLET:
contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
break;
case REACTIVE:
contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
break;
default:
contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
}
} catch (ClassNotFoundException var3) {
throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
}
}
return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
}
这里创建容器的类型 还是根据webApplicationType进行判断的,该类型为SERVLET类型,所以会通过反射装载对应的字节码,也就是AnnotationConfigServletWebServerApplicationContext
4.容器前置处理这一步主要是在容器刷新之前的准备动作。包含一个非常关键的操作:将启动类注入容器,为后续开启自动化配置奠定基础。
this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
继续跟进代码
private void prepareContext(ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
this.postProcessApplicationContext(context);
this.applyInitializers(context);
listeners.contextPrepared(context);
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
Set
调用初始化器
protected void applyInitializers(ConfigurableApplicationContext context) {
// 1. 从SpringApplication类中的initializers集合获取所有的ApplicationContextInitializer
for (ApplicationContextInitializer initializer : getInitializers()) {
// 2. 循环调用ApplicationContextInitializer中的initialize方法
Class> requiredType = GenericTypeResolver.resolveTypeArgument(
initializer.getClass(), ApplicationContextInitializer.class);
Assert.isInstanceOf(requiredType, context, "Unable to call initializer.");
initializer.initialize(context);
}
}
这里终于用到了在创建SpringApplication实例时设置的初始化器了,依次对它们进行遍历,并调用initialize方法。我们也可以自定义初始化器,并实现initialize方法,然后放入META-INF/spring.factories配置文件中Key为:org.springframework.context.ApplicationContextInitializer的value中,这里我们自定义的初始化器就会被调用,是我们项目初始化的一种方式
加载启动指定类(重点)
大家先回到文章最开始看看,在创建SpringApplication实例时,先将HelloWorldMainApplication.class存储在this.primarySources属性中,现在就是用到这个属性的时候了,我们来看看getAllSources()。
public Set
很明显,获取了this.primarySources属性,也就是我们的启动类HelloWorldMainApplication.class,我们接着看load(context, sources.toArray(new Object[0]));
protected void load(ApplicationContext context, Object[] sources) {
BeanDefinitionLoader loader = createBeanDefinitionLoader(getBeanDefinitionRegistry(context), sources);
if (this.beanNameGenerator != null) {
loader.setBeanNameGenerator(this.beanNameGenerator);
}
if (this.resourceLoader != null) {
loader.setResourceLoader(this.resourceLoader);
}
if (this.environment != null) {
loader.setEnvironment(this.environment);
}
loader.load();
}
private int load(Class> source) {
if (isGroovyPresent()
&& GroovyBeanDefinitionSource.class.isAssignableFrom(source)) {
// Any GroovyLoaders added in beans{} DSL can contribute beans here
GroovyBeanDefinitionSource loader = BeanUtils.instantiateClass(source,
GroovyBeanDefinitionSource.class);
load(loader);
}
if (isComponent(source)) {
//以注解的方式,将启动类bean信息存入beanDefinitionMap,也就是将HelloWorldMainApplication.class存入了beanDefinitionMap
this.annotatedReader.register(source);
return 1;
}
return 0;
}
被加载到 beanDefinitionMap中,后续该启动类将作为开启自动化配置的入口
通知监听器,容器已准备就绪
listeners.contextLoaded(context);
主还是针对一些日志等监听器的响应处理。
我们来看看refreshContext
private void refreshContext(ConfigurableApplicationContext context) {
this.refresh((ApplicationContext)context);
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
}
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
prepareRefresh();
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
prepareBeanFactory(beanFactory);
try {
postProcessBeanFactory(beanFactory);
invokeBeanFactoryPostProcessors(beanFactory);
registerBeanPostProcessors(beanFactory);
initMessageSource();
initApplicationEventMulticaster();
onRefresh();
registerListeners();
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
finally {
resetCommonCaches();
}
}
}
refresh方法在spring整个源码体系中举足轻重,是实现 ioc 和 aop的关键。
6.容器后置处理protected void afterRefresh(ConfigurableApplicationContext context, ApplicationArguments args) {}
扩展接口,设计模式中的模板方法,默认为空实现。如果有自定义需求,可以重写该方法。
7.发出结束执行的事件public void started(ConfigurableApplicationContext context) {
//这里就是获取的EventPublishingRunListener
Iterator var2 = this.listeners.iterator();
while(var2.hasNext()) {
SpringApplicationRunListener listener = (SpringApplicationRunListener)var2.next();
//执行EventPublishingRunListener的started方法
listener.started(context);
}
}
获取EventPublishingRunListener监听器,并执行其started方法,并且将创建的Spring容器传进去了,创建一个ApplicationStartedEvent事件,并执行ConfigurableApplicationContext 的publishEvent方法,也就是说这里是在Spring容器中发布事件,并不是在SpringApplication中发布事件,和前面的starting是不同的,前面的starting是直接向SpringApplication中的监听器发布启动事件。
8.执行Runnersprivate void callRunners(ApplicationContext context, ApplicationArguments args) {
List runners = new ArrayList();
//获取容器中所有的ApplicationRunner的Bean实例
runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
//获取容器中所有的CommandLineRunner的Bean实例
runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
AnnotationAwareOrderComparator.sort(runners);
Iterator var4 = (new LinkedHashSet(runners)).iterator();
while(var4.hasNext()) {
Object runner = var4.next();
if (runner instanceof ApplicationRunner) {
this.callRunner((ApplicationRunner)runner, args);
}
if (runner instanceof CommandLineRunner) {
this.callRunner((CommandLineRunner)runner, args);
}
}
}
因此,我们可以自定义一些ApplicationRunner或者CommandLineRunner,实现其run方法,并注入到Spring容器中,在SpringBoot启动完成后,会执行所有的runner的run方法。



