1. 程式人生 > 實用技巧 >SpringBoot啟動過程學習

SpringBoot啟動過程學習

  1 SpringApplication.run(XxxApplication.class, args);
  2 ->return run(new Class<?>[] { primarySource }, args);
  3   ->return new SpringApplication(primarySources).run(args);
  4     ->this(null, primarySources);
  5                 //##############################################################
6 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { 7 this.resourceLoader = resourceLoader; 8 Assert.notNull(primarySources, "PrimarySources must not be null"); 9 this.primarySources = new
LinkedHashSet<>(Arrays.asList(primarySources)); 10 this.webApplicationType = deduceWebApplicationType(); 11 //這一段比較費解,做了大量的class load, 還有異常個丟擲, 結果其實返回一個 SERVLET 12 //isPresent方法的核心機制就是通過反射建立指定的類,根據在建立過程中是否丟擲異常來判斷該類是否存在。
13 //############################################################## 14 private WebApplicationType deduceWebApplicationType() { 15 //當DispatcherHandler存在,並且DispatcherServlet和ServletContainer都不存在,則返回型別為WebApplicationType.REACTIVE。 16 if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null) 17 && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) { 18 return WebApplicationType.REACTIVE; 19 } 20 //當SERVLET或ConfigurableWebApplicationContext任何一個不存在時,說明當前應用為非Web應用,返回WebApplicationType.NONE。 21 //{ "javax.servlet.Servlet", "org.springframework.web.context.ConfigurableWebApplicationContext" } 22 for (String className : WEB_ENVIRONMENT_CLASSES) { 23 if (!ClassUtils.isPresent(className, null)) { 24 return WebApplicationType.NONE; 25 } 26 } 27 return WebApplicationType.SERVLET; 28 } 29 //############################################################## 30 //這一段, 就是load 型別是ApplicationContextInitializer.class 的所有類, 並建立例項 31 //"org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer", 32 //"org.springframework.boot.context.ContextIdApplicationContextInitializer", 33 //"org.springframework.boot.context.config.DelegatingApplicationContextInitializer", 34 //"org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer", 35 //"org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer", 36 //"org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener" 37 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class)); 38 39 //"org.springframework.cloud.bootstrap.BootstrapApplicationListener", 40 //"org.springframework.cloud.bootstrap.LoggingSystemShutdownListener", 41 //"org.springframework.cloud.context.restart.RestartListener", 42 //"org.springframework.boot.ClearCachesApplicationListener", 43 //"org.springframework.boot.builder.ParentContextCloserApplicationListener", 44 //"org.springframework.boot.context.FileEncodingApplicationListener", 45 //"org.springframework.boot.context.config.AnsiOutputApplicationListener", 46 //"org.springframework.boot.context.config.ConfigFileApplicationListener", 47 //"org.springframework.boot.context.config.DelegatingApplicationListener", 48 //"org.springframework.boot.context.logging.ClasspathLoggingApplicationListener", 49 //"org.springframework.boot.context.logging.LoggingApplicationListener", 50 //"org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener", 51 //"org.springframework.boot.autoconfigure.BackgroundPreinitializer" 52 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); 53 54 //這個需要這麼費勁麼...為什麼要轉了一圈才 55 this.mainApplicationClass = deduceMainApplicationClass(); 56 //############################################################## 57 private Class<?> deduceMainApplicationClass() { 58 try { 59 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); 60 for (StackTraceElement stackTraceElement : stackTrace) { 61 if ("main".equals(stackTraceElement.getMethodName())) { 62 return Class.forName(stackTraceElement.getClassName()); 63 } 64 } 65 } 66 catch (ClassNotFoundException ex) { 67 // Swallow and continue 68 } 69 return null; 70 } 71 //############################################################## 72 73 }//SpringApplication-end 74 //############################################################## 75 76 ->public ConfigurableApplicationContext run(String... args) { 77 78 StopWatch stopWatch = new StopWatch(); 79 stopWatch.start(); 80 81 ConfigurableApplicationContext context = null; 82 Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList<>(); 83 84 configureHeadlessProperty(); 85 //############################################################## 86 private void configureHeadlessProperty() { 87 System.setProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, System.getProperty(SYSTEM_PROPERTY_JAVA_AWT_HEADLESS, Boolean.toString(this.headless))); 88 } 89 //############################################################## 90 91 //前面在建構函式裡load了好多個Listener, 而現在要獲取RunListeners, 只有1個:org.springframework.boot.context.event.EventPublishingRunListener 92 SpringApplicationRunListeners listeners = getRunListeners(args); 93 //############################################################## 94 private SpringApplicationRunListeners getRunListeners(String[] args) { 95 Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; 96 return new SpringApplicationRunListeners( 97 logger, 98 getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args) 99 //############################################################## 100 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { 101 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 102 // Use names and ensure unique to protect against duplicates 103 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); 104 //############################################################## 105 public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) { 106 String factoryClassName = factoryClass.getName(); 107 return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); 108 //############################################################## 109 private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { 110 MultiValueMap<String, String> result = cache.get(classLoader); 111 if (result != null) { 112 return result; 113 } 114 115 try { 116 Enumeration<URL> urls = (classLoader != null ? 117 classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : 118 ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); 119 result = new LinkedMultiValueMap<>(); 120 while (urls.hasMoreElements()) { 121 URL url = urls.nextElement(); 122 UrlResource resource = new UrlResource(url); 123 Properties properties = PropertiesLoaderUtils.loadProperties(resource); 124 for (Map.Entry<?, ?> entry : properties.entrySet()) { 125 List<String> factoryClassNames = Arrays.asList( 126 StringUtils.commaDelimitedListToStringArray((String) entry.getValue())); 127 result.addAll((String) entry.getKey(), factoryClassNames); 128 } 129 } 130 cache.put(classLoader, result); 131 return result; 132 } catch (IOException ex) { 133 throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); 134 } 135 }//loadSpringFactories-end 136 //############################################################## 137 }//loadFactoryNames-end 138 //############################################################## 139 140 List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names); 141 //############################################################## 142 private <T> List<T> createSpringFactoriesInstances( 143 Class<T> type, 144 Class<?>[] parameterTypes, 145 ClassLoader classLoader, 146 Object[] args, 147 Set<String> names 148 ){ 149 List<T> instances = new ArrayList<>(names.size()); 150 for (String name : names) { 151 try { 152 Class<?> instanceClass = ClassUtils.forName(name, classLoader); 153 Assert.isAssignable(type, instanceClass); 154 Constructor<?> constructor = instanceClass 155 .getDeclaredConstructor(parameterTypes); 156 T instance = (T) BeanUtils.instantiateClass(constructor, args); 157 instances.add(instance); 158 } 159 catch (Throwable ex) { 160 throw new IllegalArgumentException( 161 "Cannot instantiate " + type + " : " + name, ex); 162 } 163 } 164 return instances; 165 }//createSpringFactoriesInstances-end 166 //############################################################## 167 168 AnnotationAwareOrderComparator.sort(instances); 169 return instances; 170 }//getSpringFactoriesInstances-end 171 //############################################################## 172 173 ); 174 }//getRunListeners-end 175 //############################################################## 176 177 listeners.starting(); 178 //############################################################## 179 public void starting() { 180 for (SpringApplicationRunListener listener : this.listeners) { 181 listener.starting(); 182 } 183 } 184 //############################################################## 185 186 try { 187 //封裝args, 188 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); 189 //environment, 類似properties的配置類 190 ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments); 191 //############################################################## 192 private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) { 193 // Create and configure the environment 194 ConfigurableEnvironment environment = getOrCreateEnvironment(); 195 //############################################################## 196 private ConfigurableEnvironment getOrCreateEnvironment() { 197 if (this.environment != null) { 198 return this.environment; 199 } 200 if (this.webApplicationType == WebApplicationType.SERVLET) { 201 return new StandardServletEnvironment(); 202 } 203 return new StandardEnvironment(); 204 } 205 //############################################################## 206 207 configureEnvironment(environment, applicationArguments.getSourceArgs()); 208 //############################################################## 209 protected void configureEnvironment(ConfigurableEnvironment environment, 210 String[] args) { 211 configurePropertySources(environment, args); 212 configureProfiles(environment, args); 213 } 214 //############################################################## 215 216 //這裡,非常坑!!!---> 這裡的listener 只有一個, 是EventPublishingRunListeners 217 listeners.environmentPrepared(environment); 218 //############################################################## 219 public void environmentPrepared(ConfigurableEnvironment environment) { 220 for (SpringApplicationRunListener listener : this.listeners) { 221 listener.environmentPrepared(environment); 222 //要注意這裡:ApplicationEnvironmentPreparedEvent!!!!, 這個Event一旦廣播就會進入另外一番天地 223 //********************************************************************************************** 224 @Override 225 public void environmentPrepared(ConfigurableEnvironment environment) { 226 this.initialMulticaster.multicastEvent(new ApplicationEnvironmentPreparedEvent( 227 this.application, this.args, environment)); 228 } 229 //********************************************************************************************** 230 } 231 } 232 //############################################################## 233 234 bindToSpringApplication(environment); 235 //############################################################## 236 protected void bindToSpringApplication(ConfigurableEnvironment environment) { 237 try { 238 Binder.get(environment).bind("spring.main", Bindable.ofInstance(this)); 239 } 240 catch (Exception ex) { 241 throw new IllegalStateException("Cannot bind to SpringApplication", ex); 242 } 243 } 244 //############################################################## 245 246 if (this.webApplicationType == WebApplicationType.NONE) { 247 environment = new EnvironmentConverter(getClassLoader()).convertToStandardEnvironmentIfNecessary(environment); 248 } 249 250 ConfigurationPropertySources.attach(environment); 251 //############################################################## 252 public static void attach(Environment environment) { 253 Assert.isInstanceOf(ConfigurableEnvironment.class, environment); 254 MutablePropertySources sources = ((ConfigurableEnvironment) environment).getPropertySources(); 255 PropertySource<?> attached = sources.get(ATTACHED_PROPERTY_SOURCE_NAME); 256 if (attached != null && attached.getSource() != sources) { 257 sources.remove(ATTACHED_PROPERTY_SOURCE_NAME); 258 attached = null; 259 } 260 if (attached == null) { 261 sources.addFirst(new ConfigurationPropertySourcesPropertySource(ATTACHED_PROPERTY_SOURCE_NAME,new SpringConfigurationPropertySources(sources))); 262 } 263 } 264 //############################################################## 265 return environment; 266 }//prepareEnvironment-end 267 //############################################################## 268 269 configureIgnoreBeanInfo(environment); 270 //############################################################## 271 private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) { 272 if (System.getProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) { 273 Boolean ignore = environment.getProperty("spring.beaninfo.ignore", Boolean.class, Boolean.TRUE); 274 System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME, ignore.toString()); 275 } 276 } 277 //############################################################## 278 279 Banner printedBanner = printBanner(environment); 280 //############################################################## 281 private Banner printBanner(ConfigurableEnvironment environment) { 282 if (this.bannerMode == Banner.Mode.OFF) { 283 return null; 284 } 285 ResourceLoader resourceLoader = (this.resourceLoader != null ? this.resourceLoader 286 : new DefaultResourceLoader(getClassLoader())); 287 SpringApplicationBannerPrinter bannerPrinter = new SpringApplicationBannerPrinter( 288 resourceLoader, this.banner); 289 if (this.bannerMode == Mode.LOG) { 290 return bannerPrinter.print(environment, this.mainApplicationClass, logger); 291 } 292 return bannerPrinter.print(environment, this.mainApplicationClass, System.out); 293 } 294 //############################################################## 295 296 context = createApplicationContext(); 297 //############################################################## 298 /** 299 * Strategy method used to create the {@link ApplicationContext}. By default this 300 * method will respect any explicitly set application context or application context 301 * class before falling back to a suitable default. 302 * @return the application context (not yet refreshed) 303 * @see #setApplicationContextClass(Class) 304 */ 305 protected ConfigurableApplicationContext createApplicationContext() { 306 Class<?> contextClass = this.applicationContextClass; 307 if (contextClass == null) { 308 try { 309 switch (this.webApplicationType) { 310 case SERVLET: 311 contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS); 312 break; 313 case REACTIVE: 314 contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); 315 break; 316 default: 317 contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); 318 } 319 } 320 catch (ClassNotFoundException ex) { 321 throw new IllegalStateException( 322 "Unable create a default ApplicationContext, " 323 + "please specify an ApplicationContextClass", 324 ex); 325 } 326 } 327 return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); 328 } 329 //############################################################## 330 331 exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context); 332 //############################################################## 333 private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, 334 Class<?>[] parameterTypes, Object... args) { 335 ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); 336 // Use names and ensure unique to protect against duplicates 337 Set<String> names = new LinkedHashSet<>( 338 SpringFactoriesLoader.loadFactoryNames(type, classLoader)); 339 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, 340 classLoader, args, names); 341 AnnotationAwareOrderComparator.sort(instances); 342 return instances; 343 } 344 //############################################################## 345 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 346 //這一步非常重要!!!!!!!!!!! 347 //!!!!!!!!!!!!!!!!!!!!!!!!! 348 prepareContext(context, environment, listeners, applicationArguments,printedBanner); 349 //############################################################## 350 private void prepareContext(ConfigurableApplicationContext context, 351 ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, 352 ApplicationArguments applicationArguments, Banner printedBanner) { 353 context.setEnvironment(environment); 354 postProcessApplicationContext(context); 355 356 //在這個裡面,做了初始化, initializer 有順序,DelegatingA...C...Init...是0,ContextIdA..C..Init...是2.....最大 357 applyInitializers(context); 358 //############################################################## 359 protected void applyInitializers(ConfigurableApplicationContext context) { 360 for (ApplicationContextInitializer initializer : getInitializers()) { 361 Class<?> requiredType = GenericTypeResolver.resolveTypeArgument( 362 initializer.getClass(), ApplicationContextInitializer.class); 363 Assert.isInstanceOf(requiredType, context, "Unable to call initializer."); 364 initializer.initialize(context); 365 } 366 } 367 //############################################################## 368 //第一次進來的時候, 這個listerners只有1個元素:EventPublishingRunListener 369 listeners.contextPrepared(context); 370 if (this.logStartupInfo) { 371 logStartupInfo(context.getParent() == null); 372 logStartupProfileInfo(context); 373 } 374 375 // Add boot specific singleton beans 376 context.getBeanFactory().registerSingleton("springApplicationArguments", 377 applicationArguments); 378 if (printedBanner != null) { 379 context.getBeanFactory().registerSingleton("springBootBanner", printedBanner); 380 } 381 382 // Load the sources 383 Set<Object> sources = getAllSources(); 384 Assert.notEmpty(sources, "Sources must not be empty"); 385 load(context, sources.toArray(new Object[0])); 386 listeners.contextLoaded(context); 387 } 388 //############################################################## 389 390 refreshContext(context); 391 //############################################################## 392 private void refreshContext(ConfigurableApplicationContext context) { 393 refresh(context); 394 //############################################################## 395 /** 396 * Refresh the underlying {@link ApplicationContext}. 397 * @param applicationContext the application context to refresh 398 */ 399 protected void refresh(ApplicationContext applicationContext) { 400 Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext); 401 ((AbstractApplicationContext) applicationContext).refresh(); 402 } 403 //############################################################## 404 405 if (this.registerShutdownHook) { 406 try { 407 context.registerShutdownHook(); 408 } 409 catch (AccessControlException ex) { 410 // Not allowed in some environments. 411 } 412 } 413 }//refreshContext-end 414 //############################################################## 415 416 afterRefresh(context, applicationArguments); 417 //############################################################## 418 /** 419 * Called after the context has been refreshed. 420 * @param context the application context 421 * @param args the application arguments 422 */ 423 protected void afterRefresh(ConfigurableApplicationContext context, 424 ApplicationArguments args) { 425 } 426 //############################################################## 427 428 stopWatch.stop(); 429 430 if (this.logStartupInfo) { 431 new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch); 432 //############################################################## 433 public void logStarted(Log log, StopWatch stopWatch) { 434 if (log.isInfoEnabled()) { 435 log.info(getStartedMessage(stopWatch)); 436 } 437 } 438 private String getStartupMessage() { 439 StringBuilder message = new StringBuilder(); 440 message.append("Starting "); 441 message.append(getApplicationName()); 442 message.append(getVersion(this.sourceClass)); 443 message.append(getOn()); 444 message.append(getPid()); 445 message.append(getContext()); 446 return message.toString(); 447 } 448 private StringBuilder getRunningMessage() { 449 StringBuilder message = new StringBuilder(); 450 message.append("Running with Spring Boot"); 451 message.append(getVersion(getClass())); 452 message.append(", Spring"); 453 message.append(getVersion(ApplicationContext.class)); 454 return message; 455 } 456 //############################################################## 457 } 458 459 listeners.started(context); 460 //############################################################## 461 public void started(ConfigurableApplicationContext context) { 462 for (SpringApplicationRunListener listener : this.listeners) { 463 listener.started(context); 464 } 465 } 466 //############################################################## 467 468 //第一次,runner是空 469 callRunners(context, applicationArguments); 470 //############################################################## 471 private void callRunners(ApplicationContext context, ApplicationArguments args) { 472 List<Object> runners = new ArrayList<>(); 473 runners.addAll(context.getBeansOfType(ApplicationRunner.class).values()); 474 runners.addAll(context.getBeansOfType(CommandLineRunner.class).values()); 475 AnnotationAwareOrderComparator.sort(runners); 476 for (Object runner : new LinkedHashSet<>(runners)) { 477 if (runner instanceof ApplicationRunner) { 478 callRunner((ApplicationRunner) runner, args); 479 //############################################################## 480 private void callRunner(ApplicationRunner runner, ApplicationArguments args) { 481 try { 482 (runner).run(args); 483 } 484 catch (Exception ex) { 485 throw new IllegalStateException("Failed to execute ApplicationRunner", ex); 486 } 487 } 488 //############################################################## 489 } 490 if (runner instanceof CommandLineRunner) { 491 callRunner((CommandLineRunner) runner, args); 492 //############################################################## 493 private void callRunner(CommandLineRunner runner, ApplicationArguments args) { 494 try { 495 (runner).run(args.getSourceArgs()); 496 } 497 catch (Exception ex) { 498 throw new IllegalStateException("Failed to execute CommandLineRunner", ex); 499 } 500 } 501 //############################################################## 502 } 503 } 504 } 505 //############################################################## 506 }catch (Throwable ex) { 507 handleRunFailure(context, ex, exceptionReporters, listeners); 508 //############################################################## 509 private void handleRunFailure(ConfigurableApplicationContext context, 510 Throwable exception, 511 Collection<SpringBootExceptionReporter> exceptionReporters, 512 SpringApplicationRunListeners listeners) { 513 try { 514 try { 515 handleExitCode(context, exception); 516 if (listeners != null) { 517 listeners.failed(context, exception); 518 } 519 } 520 finally { 521 reportFailure(exceptionReporters, exception); 522 if (context != null) { 523 context.close(); 524 } 525 } 526 } 527 catch (Exception ex) { 528 logger.warn("Unable to close ApplicationContext", ex); 529 } 530 ReflectionUtils.rethrowRuntimeException(exception); 531 } 532 //############################################################## 533 throw new IllegalStateException(ex); 534 } 535 536 try { 537 //第一次進來,listener只有1個 538 listeners.running(context); 539 //############################################################## 540 public void running(ConfigurableApplicationContext context) { 541 for (SpringApplicationRunListener listener : this.listeners) { 542 listener.running(context); 543 } 544 } 545 //############################################################## 546 --->EventPublishingRunListener 547 public void running(ConfigurableApplicationContext context) { 548 context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context)); 549 } 550 551 552 }catch (Throwable ex) { 553 handleRunFailure(context, ex, exceptionReporters, null); 554 throw new IllegalStateException(ex); 555 } 556 return context; 557 }

  1 BootstrapApplicationListener
  2 
  3     @Override
  4     public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
  5         ConfigurableEnvironment environment = event.getEnvironment();
  6         if (!environment.getProperty("spring.cloud.bootstrap.enabled", Boolean.class,true)) {
  7             return;
  8         }
  9         // don't listen to events in a bootstrap context
 10         if (environment.getPropertySources().contains(BOOTSTRAP_PROPERTY_SOURCE_NAME)) {
 11             return;
 12         }
 13         ConfigurableApplicationContext context = null;
 14         String configName = environment.resolvePlaceholders("${spring.cloud.bootstrap.name:bootstrap}");
 15         for (ApplicationContextInitializer<?> initializer : event.getSpringApplication().getInitializers()) {
 16             if (initializer instanceof ParentContextApplicationContextInitializer) {
 17                 context = findBootstrapContext( (ParentContextApplicationContextInitializer) initializer, configName);
 18             }
 19         }
 20         //!!!!!!!!!!!!!!!! 在這裡
 21         if (context == null) {
 22             context = bootstrapServiceContext(environment, event.getSpringApplication(),configName);
 23         }
 24         apply(context, event.getSpringApplication(), environment);
 25     }
 26     
 27     
 28     private ConfigurableApplicationContext bootstrapServiceContext(
 29             ConfigurableEnvironment environment, final SpringApplication application,
 30             String configName) {
 31         StandardEnvironment bootstrapEnvironment = new StandardEnvironment();
 32         MutablePropertySources bootstrapProperties = bootstrapEnvironment
 33                 .getPropertySources();
 34         for (PropertySource<?> source : bootstrapProperties) {
 35             bootstrapProperties.remove(source.getName());
 36         }
 37         String configLocation = environment
 38                 .resolvePlaceholders("${spring.cloud.bootstrap.location:}");
 39         Map<String, Object> bootstrapMap = new HashMap<>();
 40         bootstrapMap.put("spring.config.name", configName);
 41         // if an app (or test) uses spring.main.web-application-type=reactive, bootstrap will fail
 42         // force the environment to use none, because if though it is set below in the builder
 43         // the environment overrides it
 44         bootstrapMap.put("spring.main.web-application-type", "none");
 45         if (StringUtils.hasText(configLocation)) {
 46             bootstrapMap.put("spring.config.location", configLocation);
 47         }
 48         bootstrapProperties.addFirst(
 49                 new MapPropertySource(BOOTSTRAP_PROPERTY_SOURCE_NAME, bootstrapMap));
 50         for (PropertySource<?> source : environment.getPropertySources()) {
 51             if (source instanceof StubPropertySource) {
 52                 continue;
 53             }
 54             bootstrapProperties.addLast(source);
 55         }
 56         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 57         // Use names and ensure unique to protect against duplicates
 58         List<String> names = new ArrayList<>(SpringFactoriesLoader
 59                 .loadFactoryNames(BootstrapConfiguration.class, classLoader));
 60         for (String name : StringUtils.commaDelimitedListToStringArray(
 61                 environment.getProperty("spring.cloud.bootstrap.sources", ""))) {
 62             names.add(name);
 63         }
 64         // TODO: is it possible or sensible to share a ResourceLoader?
 65         SpringApplicationBuilder builder = new SpringApplicationBuilder()
 66                 .profiles(environment.getActiveProfiles()).bannerMode(Mode.OFF)
 67                 .environment(bootstrapEnvironment)
 68                 // Don't use the default properties in this builder
 69                 .registerShutdownHook(false).logStartupInfo(false)
 70                 .web(WebApplicationType.NONE);
 71         if (environment.getPropertySources().contains("refreshArgs")) {
 72             // If we are doing a context refresh, really we only want to refresh the
 73             // Environment, and there are some toxic listeners (like the
 74             // LoggingApplicationListener) that affect global static state, so we need a
 75             // way to switch those off.
 76             builder.application().setListeners(filterListeners(builder.application().getListeners()));
 77         }
 78         List<Class<?>> sources = new ArrayList<>();
 79         for (String name : names) {
 80             Class<?> cls = ClassUtils.resolveClassName(name, null);
 81             try {
 82                 cls.getDeclaredAnnotations();
 83             }
 84             catch (Exception e) {
 85                 continue;
 86             }
 87             sources.add(cls);
 88         }
 89         AnnotationAwareOrderComparator.sort(sources);
 90         builder.sources(sources.toArray(new Class[sources.size()]));
 91         
 92         //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 93         //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 94         //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 95         final ConfigurableApplicationContext context = builder.run();
 96         
 97                 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 98                 public ConfigurableApplicationContext run(String... args) {
 99                     if (this.running.get()) {
100                         // If already created we just return the existing context
101                         return this.context;
102                     }
103                     configureAsChildIfNecessary(args);
104                     if (this.running.compareAndSet(false, true)) {
105                         synchronized (this.running) {
106                             // If not already running copy the sources over and then run.
107                             this.context = build().run(args);
108                             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
109                                     /**
110                                      * Returns a fully configured {@link SpringApplication} that is ready to run.
111                                      * @return the fully configured {@link SpringApplication}.
112                                      */
113                                     public SpringApplication build() {
114                                         return build(new String[0]);
115                                     }
116                                     
117                                     這裡又回到了SpringApplication的啟動
118                                     
119                             //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
120                         }
121                     }
122                     return this.context;
123                 }
124                 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
125         
126         // gh-214 using spring.application.name=bootstrap to set the context id via
127         // `ContextIdApplicationContextInitializer` prevents apps from getting the actual
128         // spring.application.name
129         // during the bootstrap phase.
130         context.setId("bootstrap");
131         // Make the bootstrap context a parent of the app context
132         addAncestorInitializer(application, context);
133         // It only has properties in it now that we don't want in the parent so remove
134         // it (and it will be added back later)
135         bootstrapProperties.remove(BOOTSTRAP_PROPERTY_SOURCE_NAME);
136         mergeDefaultProperties(environment.getPropertySources(), bootstrapProperties);
137         return context;
138     }