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); } }