SpringBoot启动过程
研究SpringBoot的自动装配,同时也想弄明白它的启动流程,然后就有了这篇随笔。
SpringBoot的启动一般都是从main方法开始,这也是它的第一步
//SpringBoot注解,用于启动的
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
//启动类静态的run方法
SpringApplication.run(DemoApplication.class, args);
}
}
第二步就是通过构造方法在创建SpringApplication对象时,会初始化对象的值
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));
//通过调用deduceFromClasspath方法判断web应用是什么类型的
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//将启动注册初始化类通过工厂类得到实例放到ArrayList列表
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//将应用上下文初始化类通过工厂类得到实例进行初始化
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//ApplicationListener监听器类通过工厂类得到实例放进监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//得到main方法类实例
this.mainApplicationClass = this.deduceMainApplicationClass();
}
第三步就是会执行对应的run方法,run方法源码为:
public ConfigurableApplicationContext run(String... args) {
//获取启动时的时间毫秒数
long startTime = System.nanoTime();
//创建一个启动上下文容器
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
//设置Headless模式属性,Headless模式模式代表当缺少外设依赖时使用此模式
this.configureHeadlessProperty();
//创建监听器,监听器开始启动
SpringApplicationRunListeners listeners = this.getRunListeners(args);
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//创建一个应用属性对象
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建应用的上下文环境,从配置的application.properties等配置文件中读取
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//用来忽略所有自定义的BeanInfo类的搜索
this.configureIgnoreBeanInfo(environment);
//打印banner标志
Banner printedBanner = this.printBanner(environment);
//创建应用程序上下文
context = this.createApplicationContext();
//设置应用启动器
context.setApplicationStartup(this.applicationStartup);
//对bean,属性,标志进行初始化生成和处理
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//进行上下文刷新工作,如对系统关闭周期钩子重置内容等等
this.refreshContext(context);
this.afterRefresh(context, applicationArguments);
//得到启动时长
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
//告诉那个应用启动用了多少秒
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
//启动完成通知
listeners.started(context, timeTakenToStartup);
//如果有ApplicationRunner或者CommandLineRunner类型的bean,就会触发调用
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
return context;
} catch (Throwable var11) {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
在上面的方法中有这一行代码 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); 这一行代码涉及到了环境处理,属性设置等等。针对涉及到的this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);方法进行解析
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
//根据web应用类型选择响应的应用容器环境
ConfigurableEnvironment environment = this.getOrCreateEnvironment();
//进行环境参数配置,但是此方法先去查看是否需要转换服务,再有条件地进行环境参数配置
this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
//通过判断环境中的是否含有onfigurationProperties的属性进行不同的处理
ConfigurationPropertySources.attach((Environment)environment);
//环境初始化,加载生效的profile等资源
listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);
//配置属性中添加defaultProperties默认配置
DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
//判断环境属性中是否包含spring.main.environment-prefix键,如果包含的话,则会报出异常,异常内容第二个参数
Assert.state(!((ConfigurableEnvironment)environment).containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");
//将配置属性与各种组件进行绑定
this.bindToSpringApplication((ConfigurableEnvironment)environment);
//判断是否需要进行容器类型转换
if (!this.isCustomEnvironment) {
environment = this.convertEnvironment((ConfigurableEnvironment)environment);
}
//通过判断环境中的是否含有onfigurationProperties的属性进行不同的处理
ConfigurationPropertySources.attach((Environment)environment);
return (ConfigurableEnvironment)environment;
}
在上面run方法的源码中有这行代码this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);,查看这个方法源码
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) {
context.setEnvironment(environment);
//应用程序对自定义的加载器进行加载
this.postProcessApplicationContext(context);
//初始化上下文
this.applyInitializers(context);
//调用监听器
listeners.contextPr epared(context);
//往下追的话也是调用各种监听器
bootstrapContext.close(context);
//日志输出,输出了一行JDK信息和进程号,以及生效的profile模式内容
if (this.logStartupInfo) {
this.logStartupInfo(context.getParent() == null);
this.logStartupProfileInfo(context);
}
//创建一个bean工厂
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//利用工厂进行注册
beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
if (printedBanner != null) {
beanFactory.registerSingleton("springBootBanner", printedBanner);
}
if (beanFactory instanceof AbstractAutowireCapableBeanFactory) {
((AbstractAutowireCapableBeanFactory)beanFactory).setAllowCircularReferences(this.allowCircularReferences);
if (beanFactory instanceof DefaultListableBeanFactory) {
((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
}
//进行懒加载
if (this.lazyInitialization) {
context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
}
//加载资源
Set<Object> sources = this.getAllSources();
Assert.notEmpty(sources, "Sources must not be empty");
this.load(context, sources.toArray(new Object[0]));
listeners.contextLoaded(context);
}
生于忧患,死于安乐