本文分析SpringBoot启动类及其原理主要是从一下俩个方面来分析的
- 解析@SpringBootApplication
- 解析run方法
解析@SpringBootApplication
@SpringBootConfiguration
首先这是一个配置类,继承于@Configuration,本身只是说明这是一个SpringBoot项目的配置类,功能与@Configuration一样,使得Spring容器知道需要跟处理@Configuration注解的类一样处理这个类。
@EnableAutoConfiguration
故名思意这是一个自动装配
一是收集所有spring.factories中EnableAutoConfiguration相关bean的类,初始化为一个相关的bean;
二是将得到的类注册到spring容器中,启动自动化置。 总的来说@EnableAutoConfiguration是借助@Import的帮助,将所有符合自动配置条件的bean定义加载到IoC容器,
@ComponetScan
这是一个基于注解的类扫描
用于进行包扫描,检查类是否使用了@Controller,@Service等注解,有则获取这些类创建对应的bean对象注册到Spring容器。
解析run方法
在解析run方法之前,我们需要了解SpringApplication类主要做了哪四件事情。
根据启动类中SpringApplication的源码中的构造函数我们可以得知
//先把主类保存起来
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//1、判断运行项目的类型
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//2、扫描当前路径下META-INF/spring.factories文件的,加载ApplicationContextInitializer
//接口实例
setInitializers((Collection)
getSpringFactoriesInstances(ApplicationContextInitializer.class));
//3、扫描当前路径下META-INF/spring.factories文件的,加载ApplicationListener接口实例
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//4、判断并设置main方法的定义类,找到运行的主类
this.mainApplicationClass = deduceMainApplicationClass();
接下来我们来正式解析run方法
下面是一个application运行的时序图
接下来我们来看看 ConfigurableApplicationContext new出来的run的源码
public ConfigurableApplicationContext run(String... args) {
// 1、这个是一个计时器
StopWatch stopWatch = new StopWatch();
stopWatch.start();
//2、设置了一些环境变量
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
configureHeadlessProperty();
//3、获取事件监听器SpringApplicationRunListener类型,并且执行starting()方法
SpringApplicationRunListeners listeners = getRunListeners(args);
listeners.starting();
try {
//4、把参数args封装成DefaultApplicationArguments
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//5、这个很重要准备环境了,并且把环境跟spring上下文绑定好,并且执行
//environmentPrepared()方法
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//6、判断一些环境的值,并设置一些环境的值
configureIgnoreBeanInfo(environment);
//7、打印banner
Banner printedBanner = printBanner(environment);
//8、创建上下文,根据项目类型创建上下文
context = createApplicationContext();
//9、获取异常报告事件监听
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//10、准备上下文,执行完成后调用contextPrepared()方法,contextLoaded()方法
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//11、这个是spring启动的代码了,这里就回去里面就回去扫描并且初始化单实列bean了
//这个refreshContext()加载了bean,还启动了内置web容器
//最核心的一步,将之前通过@EnableAutoConfiguration获取的所有配置以及其他形式的IoC容
//器配置加载到已经准备完毕的ApplicationContext。
refreshContext(context);
afterRefresh(context, applicationArguments);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//12、执行ApplicationRunListeners中的started()方法
listeners.started(context);
//13、执行Runner(ApplicationRunner和CommandLineRunner)
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
handleRunFailure(context, listeners, exceptionReporters, ex);
throw new IllegalStateException(ex);
}
listeners.running(context);
return context;
}
为了方便理解源码我们可以看一下一下的run方法的分析图。
到此关于SpringBoot启动类及其原理的简单分析就已经完成了。再此感谢吴同学提供的素材。