【Spring boot】启动过程源码分析( 二 )

private Class<?> deduceMainApplicationClass() {try {// 获取调用栈数组StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();// 找到调用栈中的main方法!for (StackTraceElement stackTraceElement : stackTrace) {if ("main".equals(stackTraceElement.getMethodName())) {return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null;}核心的启动方法:run(String... args)public ConfigurableApplicationContext run(String... args) {// 开始时间long startTime = System.nanoTime();// 创建引导启动器 , 类似一个ApplicationContext,可以往里面添加一些对象 。DefaultBootstrapContext bootstrapContext = createBootstrapContext();// spring容器对象,开始的时候为空ConfigurableApplicationContext context = null;// 与awt有关,一般用不上configureHeadlessProperty();// spring boot的启动监听器// 从spring.factories中获取SpringApplicationRunListener对象的值// 默认会拿到EventPublishingRunListener,他会启动各个地方的ApplicationEvent事件 。SpringApplicationRunListeners listeners = getRunListeners(args);// 发布开始启动的事件:ApplicationstartingEventlisteners.starting(bootstrapContext, this.mainApplicationClass);try {// 把run方法的参数进行封装ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);// 准备environment对象:包括操作系统、jvm、ymal、properties....配置// 发布一个ApplicationEnvironmentPreparedEvent事件 。ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);// 默认spring.beaninfo.ignore为true,表示不需要jdk去缓存BeanInfo信息,spring自己缓存 。// 这里是spring在创建bean的时候会利用jdk的一些工具来解析一个类的相关信息,jdk在解析一个类的信息的时候会进行缓存,这里就是禁止了jdk的缓存 。configureIgnoreBeanInfo(environment);// 打印BannerBanner printedBanner = printBanner(environment);// 根据应用类型 , 创建spring容器context = createApplicationContext();// jdk9的一个机制 , 默认没做任何操作context.setApplicationStartup(this.applicationStartup);// 准备容器的操作// 利用ApplicationContextInitializer初始化spring容器// 发布ApplicationContextInitializedEvent(容器初始化完成)事件// 发布BootstrapContextClosedEvent(关闭引导容器)事件// 注册primarySources类(run方法存进来的配置类)// 发布ApplicationPreparedEvent事件prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);// refresh容器:解析配置类、扫描、启动webServer 。spring相关的逻辑!refreshContext(context);// 空方法 , 类似spring的onRefresh方法,可以由子类实现 。afterRefresh(context, applicationArguments);// 启动的事件Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);}// 发布一个ApplicationStartedEvent事件,表示spring已经启动完成listeners.started(context, timeTakenToStartup);// 从spring容器中获取ApplicationRunner和CommandLineRunner,并执行他的run方法 。// 这俩个可以自己定义BeancallRunners(context, applicationArguments);}catch (Throwable ex) {// 失败之后,发布一个失败的事件:ApplicationFailedEventhandleRunFailure(context, ex, listeners);throw new IllegalStateException(ex);}try {// 计算下事件Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);// 一切都成功 , 发布ApplicationStartedEvent事件listeners.ready(context, timeTakenToReady);}catch (Throwable ex) {// 失败之后 , 发布一个失败的事件:ApplicationFailedEventhandleRunFailure(context, ex, null);throw new IllegalStateException(ex);}return context;}创建引导启动器private DefaultBootstrapContext createBootstrapContext() {// 构建一个DefaultBootstrapContext对象,这个对象是2.4.0之后才会有!DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();// 利用bootstrapRegistryInitializers初始化bootstrapContext 。可以在spring.factories中设置bootstrapRegistryInitializersthis.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));return bootstrapContext;}准备environmentprivate ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {// Create and configure the environment这句话是源码中本身的注释!// 创建ApplicationServletEnvironment 。ConfigurableEnvironment environment = getOrCreateEnvironment();// 添加SimpleCommandLinePropertySource放在首位configureEnvironment(environment, applicationArguments.getSourceArgs());// 把所有的PropertySource封装为ConfigurationPropertySourcesPropertySource,然后添加到environment中,放在首位!ConfigurationPropertySources.attach(environment);// 发布ApplicationEnvironmentPreparedEvent(应用Environment准备完成)事件,表示环境已经准备好了 。默认EnvironmentPostProcessorApplicationListener去处理这个事件!listeners.environmentPrepared(bootstrapContext, environment);// 把DefaultProperties放到最后DefaultPropertiesPropertySource.moveToEnd(environment);// 环境中spring.main.environment-prefix参数校验Assert.state(!environment.containsProperty("spring.main.environment-prefix"), "Environment prefix cannot be set via properties.");// 环境中spring.main参数校验bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = convertEnvironment(environment);}ConfigurationPropertySources.attach(environment);return environment;}

推荐阅读