最近看springBoot,研究一下springBoot启动源码
springboot启动
- 初始化SpringApplication
- 调用SpringApplication的run方法启动
主入口程序
@SpringBootApplication
public class PracticeBootStarterApplication {
private static final Logger logger = LoggerFactory.getLogger(PracticeBootStarterApplication.class);
public static void main(String[] args) {
SpringApplication.run(PracticeBootStarterApplication.class, args);
}
}
SpringApplication.java
//第一步调用
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);
}
//第三步调用
public SpringApplication(Class<?>... primarySources) {
this(null, primarySources);
}
//SpringApplication构造方法
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
//设置resourceLoader 默认时为null
this.resourceLoader = resourceLoader;
//判断启动类不为空
Assert.notNull(primarySources, "PrimarySources must not be null");
//设置启动类为主source
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
//设置web应用类型,main方法启动时类型为WebApplicationType.SERVLET
this.webApplicationType = deduceWebApplicationType();
//设置初始化类实例(从spring-boot-autoconfigure包中META-INF/spring.factoryes配置文件中查找对应的类名)
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//设置初始化监听器实例(从spring-boot-autoconfigure包中META-INF/spring.factoryes配置文件中查找对应的类名)
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//设置主入口
this.mainApplicationClass = deduceMainApplicationClass();
}
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();
//设置Headless模式(
//Headless模式是系统的一种配置模式。在系统可能缺少显示设备、键盘或鼠标这些外设的情况下可以使用该模式。
//Headless模式虽然不是我们愿意见到的,但事实上我们却常常需要在该模式下工作,尤其是服务器端程序开发者。
//因为服务器(如提供Web服务的主机)往往可能缺少前述设备,但又需要使用他们提供的功能,生成相应的数据,
//以提供给客户端(如浏览器所在的配有相关的显示设备、键盘和鼠标的主机)。)
configureHeadlessProperty();
//获取SpringApplicationRunListener实例(从spring-boot包中META-INF/spring.factoryes配置文件中查找对应的类名)
SpringApplicationRunListeners listeners = getRunListeners(args);
//启动监听器
listeners.starting();
try {
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备启动环境(可理解为把配置文件读取到environment对象中)
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
configureIgnoreBeanInfo(environment);
//打印banner信息(在environment获取spring.banner.location属性获取banner地址,默认在classpath下的banner.txt)
Banner printedBanner = printBanner(environment);
//创建ConfigurableApplicationContext
context = createApplicationContext();
//获取异常分析器实例(从spring-boot包中META-INF/spring.factoryes配置文件中查找对应的类名org.springframework.boot.diagnostics.FailureAnalyzers)
exceptionReporters = getSpringFactoriesInstances(
SpringBootExceptionReporter.class,
new Class[] { ConfigurableApplicationContext.class }, context);
//设置context的environment、listeners等属性
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//1、刷新Context(调用AbstractApplicationContext的refresh)
//2、context设置shutdownHook
refreshContext(context);
//暂时是空方法,扩展使用
afterRefresh(context, applicationArguments);
stopWatch.stop();
//打印启动时间(单位毫秒)
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//启动监听器
listeners.started(context);
//通过implements ApplicationRunner扩展的spring容器启动时执行的动作
//下面以MyRunner为例
callRunners(context, applicationArguments);
}
catch (Throwable ex) {
//分析并打印异常原因
handleRunFailure(context, ex, exceptionReporters, listeners);
throw new IllegalStateException(ex);
}
try {
//监听器启动
listeners.running(context);
}
catch (Throwable ex) {
handleRunFailure(context, ex, exceptionReporters, null);
throw new IllegalStateException(ex);
}
return context;
}
其中refreshContext(context)调用applicationContext的refresh方法
自定义runner
@Component
public class MyRunner implements ApplicationRunner {
public void run(ApplicationArguments args) throws Exception {
System.out.println("--123--");
}
}