启动
入口
@SpringBootApplication
public class XlcqqApplication {
public static void main(String[] args) {
SpringApplication.run(XlcqqApplication.class, args);
}
}
整个项目将从SpringApplication.run()这个关键方法启动,SpringApplication是引导SpringBoot启动的一个工具类,这个类提供的run()是一个关键方法,其中最重要的功能就是创建spring的context
创建SpringContext
run()源码片段如下
try {
......
context = createApplicationContext();
......
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
......
}
可见就是调用了createApplicationContext()来创建context的,进入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);
}
}
会发现SpringBoot将根据webApplicationType属性来创建对应的context实例,预定义的两个实例class为
public static final String DEFAULT_SERVLET_WEB_CONTEXT_CLASS = "org.springframework.boot."
+ "web.servlet.context.AnnotationConfigServletWebServerApplicationContext";
public static final String DEFAULT_REACTIVE_WEB_CONTEXT_CLASS = "org.springframework."
+ "boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext";
至此,便知道SpringBoot启动Spring其实就只是根据当前环境,创建了AnnotationConfigServletWebServerApplicationContext或者AnnotationConfigReactiveWebServerApplicationContext二者之一来作为Spring的context。
加载Spring的Bean
在上面的run()方法中,创建了spring context之后,接着要加载bean,这是在第二步 prepareContext()中完成的。源码如下:
private void prepareContext(ConfigurableApplicationContext context,
ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
...... //一系列准备工作
load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
上面的方法中,最后用调用了load()这个方法,进入load()
protected void load(ApplicationContext context, Object[] sources) {
if (logger.isDebugEnabled()) {
logger.debug(
"Loading source " + StringUtils.arrayToCommaDelimitedString(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();
}
这个方法中,创建了一个 BeanDefinitionLoader的实例loader,而这个loader,就是spring中用来加载bean的loader,从这里开始,后续也就是在执行spring原有的加载bean的一系列功能了。
小结:
对于以上SpringBoot启动的三步总结如下:
- 首先SpringBoot的入口main函数中,调用了SpringApplication.run()方法,这个方法主要用途是创建一个spring context实例
- 在run()中,将根据当前项目环境,创建一个对应的spring context
- 创建了srping context之后,会委托spring原有的BeanDefinitionLoader来加载bean
以上是SpringBoot启动的主要步骤,但是非常粗略,其中还涉及到非常多的事情,例如一个starter是如何做到自动配置启动的,Spring WEB启动的时候是如何自动启动tomcat的等等。