SpringApplication源码剖析(一)——构造方法
之前通过看了AbstractApplicationContext.class、DefaultListableBeanFactory.class、AbstractBeanFactory.class几个类基本了解到了SpringIoC相关特性的原理具体代码实现。从这篇文章开始将打算了解以下SpringBoot应用的启动过程。SpringBoot应用入口是SpringApplication.run()方法,因此从这个方法为入口,看一下相关的源码。
看源码
看这个源码前,我一般会先到spring官网上看看有没有相关的资料,把一些定义先有个初步的概念,比如@SpringApplication注解、BeanPostProcessor、SpringBoot starter等;对定义有了印象后,会带着些疑问去看源码;最后会逐步调试看一下运行结果。比如在看SpringApplication源码时,我会使用下列例子:
@SpringBootApplication
public class Main {
public static void main(String[] args){
SpringApplication.run(Main.class);
}
}
打断点逐步看输出结果。
构造方法
在阅读run()方法的源码时,发现有些类属性是在构造方法中初始化的,因此先写一篇关于构造方法的笔记,记录以下几个后面会用到的比较特殊的属性。
构造方法源码:
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 = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = this.deduceMainApplicationClass();
}
this.sources = new LinkedHashSet();
spring应用的源source?
this.bannerMode = Mode.CONSOLE;
banner的模式,banner是指SpringBoot启动的时候打印的:
一共三种枚举:LOG、CONSOLE、OFF
this.addCommandLineProperties = true;
若addCommandLineProperties设置为true,则如果启动时命令行传入的参数不为空,则把参数以SimpleCommandLinePropertySource对象实例形式添加到environment.getPropertySources()中
相关代码:
protected void configurePropertySources(ConfigurableEnvironment environment, String[] args) {
MutablePropertySources sources = environment.getPropertySources();
DefaultPropertiesPropertySource.ifNotEmpty(this.defaultProperties, sources::addLast);
if (this.addCommandLineProperties && args.length > 0) {
String name = "commandLineArgs";
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));
}
}
}
this.addConversionService = true;
相关代码主要有两处:
1、设置环境变量时,若addConversionService为true,则把sharedInstance注入到ConfigurableEnvironment中
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) {
if (this.addConversionService) {
ConversionService conversionService = ApplicationConversionService.getSharedInstance();
environment.setConversionService((ConfigurableConversionService)conversionService);
}
this.configurePropertySources(environment, args);
this.configureProfiles(environment, args);
}
2、若addConversionService为true,则把sharedInstance注入到beanFactory中
protected void postProcessApplicationContext(ConfigurableApplicationContext context) {
......
if (this.addConversionService) {
context.getBeanFactory().setConversionService(ApplicationConversionService.getSharedInstance());
}
}
this.registerShutdownHook = true;
若设置为true,则起一条线程监听当前线程发生shutdown时调用AbstractApplicationContext.doClose()方法。
相关代码:
private void refreshContext(ConfigurableApplicationContext context) {
if (this.registerShutdownHook) {
try {
context.registerShutdownHook();
} catch (AccessControlException var3) {
}
}
this.refresh((ApplicationContext)context);
}
public void registerShutdownHook() {
if (this.shutdownHook == null) {
this.shutdownHook = new Thread("SpringContextShutdownHook") {
public void run() {
synchronized(AbstractApplicationContext.this.startupShutdownMonitor) {
AbstractApplicationContext.this.doClose();
}
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
this.lazyInitialization = false;
设置bean定义是否默认为懒加载,若设置为true,则会添加LazyInitializationBeanFactoryPostProcessor到context的beanFactoryPostProcessor列表中,遍历所有BeanDefinition,若没有设置lazyInit属性,则默认修改为true。
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
默认的applicationContext工厂,根据webApplicationType返回对应的context。
ApplicationContextFactory DEFAULT = (webApplicationType) -> {
try {
switch(webApplicationType) {
case SERVLET:
return new AnnotationConfigServletWebServerApplicationContext();
case REACTIVE:
return new AnnotationConfigReactiveWebServerApplicationContext();
default:
return new AnnotationConfigApplicationContext();
}
} catch (Exception var2) {
throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2);
}
};
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
SpringApplication构造函数传入的class参数,存储在primarySource属性中
this.webApplicationType = WebApplicationType.deduceFromClasspath();
根据不同的webApplicationType生成对应的ApplicationContext、Enviroment属性。判断条件:
1、若存在DispatcherHandler,则webApplicationType=REACTIVE
2、若存在"javax.servlet.Servlet"、"org.springframework.web.context.ConfigurableWebApplicationContext"都有加载,则返回SERVLET,(SERVLET_INDICATOR_CLASSES = new String[]{“javax.servlet.Servlet”, “org.springframework.web.context.ConfigurableWebApplicationContext”};)
3、否则返回NONE
相关判断代码:
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;
}
}
this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class));
获取所有Bootstrapper.class类型bean,在BoostrapperContext初始化阶段会调用所有的Boostrapper的initialize方法初始化context:
private DefaultBootstrapContext createBootstrapContext() {
DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
this.bootstrappers.forEach((initializer) -> {
initializer.intitialize(bootstrapContext);
});
return bootstrapContext;
}
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
获取所有ApplicationContextInitializer.class类型bean,在ApplicationContext初始化阶段会调用所有initialzer初始化context,发生在BeanDefinition加载之前。
默认的Initializer有7个:
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
加载所有ApplicationListener,监听Application生命周期事件,默认的Listener有9个:
this.mainApplicationClass = this.deduceMainApplicationClass();
根据调用栈找到main方法所在类。
private Class<?> deduceMainApplicationClass() {
try {
StackTraceElement[] stackTrace = (new RuntimeException()).getStackTrace();
StackTraceElement[] var2 = stackTrace;
int var3 = stackTrace.length;
for(int var4 = 0; var4 < var3; ++var4) {
StackTraceElement stackTraceElement = var2[var4];
if ("main".equals(stackTraceElement.getMethodName())) {
return Class.forName(stackTraceElement.getClassName());
}
}
} catch (ClassNotFoundException var6) {
}
return null;
}