1、前言java
前两篇文章咱们主要经过源码分析了spring boot 加载配置文件的一些流程,接下来咱们继续分析他是怎么组装,怎么运行起来的。期间他经过什么样的方式加载咱们的核心配置 application.yml .spring
2、源码分析app
咱们回到咱们启动用的主类less
@SpringBootApplication public class StudyApplication { public static void main(String[] args) { SpringApplication.run(StudyApplication.class, args); } }
进入SpringApplication.run()方法源码分析
public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) { return run(new Class<?>[] { primarySource }, args); }
这个方法以前介绍过,咱们继续看他的重载方法run()性能
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
前两节咱们已经讲了new SpringApplication(primarySources)里的内容,下面咱们看看他的run(args)主要作了些什么this
/** * 运行 Spring application, 建立和刷新成一个新的应用上下文 * {@link ApplicationContext}. * @param args the application arguments (usually passed from a Java main method) * @return a running {@link ApplicationContext} */ public ConfigurableApplicationContext run(String... args) { StopWatch stopWatch = new StopWatch();//做为性能检测的一个类 stopWatch.start();//检测性能开始点 ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>();//错误报告list configureHeadlessProperty(); SpringApplicationRunListeners listeners = getRunListeners(args);//经过args获取运行的监听器 listeners.starting();//开启监听器 try { ApplicationArguments applicationArguments = new DefaultApplicationArguments( args);//args封装到ApplicationArguments应用参数 ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);//将监听器listeners和应用参数applicationArguments封装到配置环境ConfigurableEnvironment中去 configureIgnoreBeanInfo(environment);//配置一些要忽略的bean信息 Banner printedBanner = printBanner(environment); context = createApplicationContext();//建立ApplicationContext exceptionReporters = getSpringFactoriesInstances( SpringBootExceptionReporter.class, new Class[] { ConfigurableApplicationContext.class }, context);//建立错误报告list prepareContext(context, environment, listeners, applicationArguments, printedBanner);//将environment配置环境,listeners监听器列表,applicationArguments应用参数,printedBanner封装到context中 refreshContext(context);刷新应用上下文context afterRefresh(context, applicationArguments);//在应用上下文被刷新以后调用 stopWatch.stop();//检测性能结束点 if (this.logStartupInfo) {//日志记录,这里就用到了开始代码提到的性能检测点stopWatch new StartupInfoLogger(this.mainApplicationClass) .logStarted(getApplicationLog(), stopWatch); } listeners.started(context);//通知监听器context已经启动 callRunners(context, applicationArguments);启动 } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, listeners); throw new IllegalStateException(ex); } try { listeners.running(context);//通知监听器context正在运行 } catch (Throwable ex) { handleRunFailure(context, ex, exceptionReporters, null); throw new IllegalStateException(ex); } return context; }
未完待续。。。debug
ConfigFileApplicationListener 主要业务加载类,具体的追踪方法会在6月1日儿童节揭晓。
ConfigFileApplicationListener.Loader.load(PropertySourceLoader loader, String location, Profile profile,DocumentFilter filter, DocumentConsumer consumer) private void load(PropertySourceLoader loader, String location, Profile profile, DocumentFilter filter, DocumentConsumer consumer) { try { Resource resource = this.resourceLoader.getResource(location); String description = getDescription(location, resource); if (profile != null) { description = description + " for profile " + profile; } if (resource == null || !resource.exists()) { this.logger.trace("Skipped missing config " + description); return; } if (!StringUtils.hasText( StringUtils.getFilenameExtension(resource.getFilename()))) { this.logger.trace("Skipped empty config extension " + description); return; } String name = "applicationConfig: [" + location + "]"; List<Document> documents = loadDocuments(loader, name, resource); if (CollectionUtils.isEmpty(documents)) { this.logger.trace("Skipped unloaded config " + description); return; } List<Document> loaded = new ArrayList<>(); for (Document document : documents) { if (filter.match(document)) { addActiveProfiles(document.getActiveProfiles()); addProfiles(document.getIncludeProfiles()); loaded.add(document); } } Collections.reverse(loaded); if (!loaded.isEmpty()) { loaded.forEach((document) -> consumer.accept(profile, document)); this.logger.debug("Loaded config file " + description); } } catch (Exception ex) { throw new IllegalStateException("Failed to load property " + "source from location '" + location + "'", ex); } }