Spring Boot项目启动原理初探

时间:2021-11-23 05:36:48

Spring Boot是利用 SpringApplication类的static的 run 方法进行启动的,调用的图:

Spring Boot项目启动原理初探

//调用示例:

public static void main(String[] args) throws Exception {
  SpringApplication.run(Examples.class, args);
}

SpringApplication类提供了两个static的run方法:

public static ConfigurableApplicationContext run(Object source, String... args) {
return run(new Object[] { source }, args);
}


public static ConfigurableApplicationContext run(Object[] sources, String[] args) {
return new SpringApplication(sources).run(args);
}

上面两个方法其实就是一个,最终都会创建一个SringApplication实例,在构造时会处理传入的 sources 参数,SpringApplication构造方法如下:

public SpringApplication(Object... sources) {
    initialize(sources);
}
private void initialize(Object[] sources) {
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
this.webEnvironment = deduceWebEnvironment(); //根据当前项目是否包含相应的类,来推断当前项目是否是web项目
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.
class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.
class)); this.mainApplicationClass = deduceMainApplicationClass();
}

getSpringFactoriesInstances
方法是用来
查找每个jar和类路径下的/META-INF/spring.factories文件,并获取其中的特定接口的配置的,例如在spring-boot-autoconfigure-1.5.2.RELEASE.jar中的spring.factories文件,其中对
ApplicationContextInitializer接口和 ApplicationListener接口的配置如下:
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.AutoConfigurationReportLoggingInitializer

# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer

上面的代码完成初始化之后,紧接着就是调用SpringApplication类的实例 run方法,代码如下:

public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch
= new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context
= null;
FailureAnalyzers analyzers
= null;
configureHeadlessProperty();
SpringApplicationRunListeners listeners
= getRunListeners(args);
listeners.starting();
try {
ApplicationArguments applicationArguments
= new DefaultApplicationArguments(
args);
ConfigurableEnvironment environment
= prepareEnvironment(listeners,
applicationArguments);
Banner printedBanner
= printBanner(environment);
context
= createApplicationContext();
analyzers
= new FailureAnalyzers(context);
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
refreshContext(context);
afterRefresh(context, applicationArguments);
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);
}
}

SpringApplication类的实例 run方法做了如下这些事:

1.创建了一个 ApplicationContext 实例,在 createApplicationContext()方法中完成了实例的创建

   webEnvironment属性为true,则创建org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext 类的实例,否则创建 org.springframework.context.annotation.AnnotationConfigApplicationContext的实例

protected ConfigurableApplicationContext createApplicationContext() {
Class
<?> contextClass = this.applicationContextClass;
if (contextClass == null) {
try {
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);
}
}
return (ConfigurableApplicationContext) BeanUtils.instantiate(contextClass);
}

 

2.产生一个CommandLinePropertySource用来把命令行的参数转化为spring容器启动需要的一些属性配置

3. 启动 ApplicationContext 容器加载Bean

3.待定(Trigger any CommandLineRunner beans)

4.一般在启动类上要加@EnableAutoConfiguration这个注解,用来获取各种配置信息, 

   (1)这个注解所加的启动类的包将作为Spring容器扫描Bean的basePackage属性

5.项目中的一些Bean的配置可以是xml方式,但Spring Boot建议使用@Configuration注解

 

总结一下:

     SpringApplication类的static的 run 方法做的事就是先实例化一个 SpringApplication实例,然后调用其 initialize 方法进行一些初始化工作,接着就调用SpringApplication实例的run方法启动容器。