SpringBoot启动过程学习
Springboot2.0.3 release.jar spring.factories //////////////////////////////////////////////////////////////////////////////////////////// # PropertySource Loaders org.springframework.boot.env.PropertySourceLoader=\ org.springframework.boot.env.PropertiesPropertySourceLoader,\ org.springframework.boot.env.YamlPropertySourceLoader # Run Listeners----->第一个启动的Listener org.springframework.boot.SpringApplicationRunListener=\ org.springframework.boot.context.event.EventPublishingRunListener # Error Reporters org.springframework.boot.SpringBootExceptionReporter=\ org.springframework.boot.diagnostics.FailureAnalyzers # Application Context Initializers org.springframework.context.ApplicationContextInitializer=\ org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\ org.springframework.boot.context.ContextIdApplicationContextInitializer,\ org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\ org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer # Application Listeners org.springframework.context.ApplicationListener=\ org.springframework.boot.ClearCachesApplicationListener,\ org.springframework.boot.builder.ParentContextCloserApplicationListener,\ org.springframework.boot.context.FileEncodingApplicationListener,\ org.springframework.boot.context.config.AnsiOutputApplicationListener,\ org.springframework.boot.context.config.ConfigFileApplicationListener,\ org.springframework.boot.context.config.DelegatingApplicationListener,\ org.springframework.boot.context.logging.ClasspathLoggingApplicationListener,\ org.springframework.boot.context.logging.LoggingApplicationListener,\ org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener # Environment Post Processors org.springframework.boot.env.EnvironmentPostProcessor=\ org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\ org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor,\ org.springframework.boot.env.SystemEnvironmentPropertySourceEnvironmentPostProcessor # Failure Analyzers org.springframework.boot.diagnostics.FailureAnalyzer=\ org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.BindValidationFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.UnboundConfigurationPropertyFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ConnectorStartFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyNameFailureAnalyzer,\ org.springframework.boot.diagnostics.analyzer.InvalidConfigurationPropertyValueFailureAnalyzer # FailureAnalysisReporters org.springframework.boot.diagnostics.FailureAnalysisReporter=\ org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
执行顺序
1.listener.starting 2.listener.environmentPrepared >>触发BootstrapApplicationListener,调用onApplicationEvent, 然后创建SpringApplicationBuilder builder = new SpringApplicationBuilder(), 又回到SpringApplication.run. 然后1,2(中间短路),3,4,5执行一遍. 3.listener.contextPrepared >>context.refresh 4.listener.started 5.listener.running
山穷水尽的时候, 发现别人启动的一个报错, 终于摸清楚了调用栈.
从这个对战里可以看出来.SpringApplication.prepareEnvironment 这一步一直走,触发事件, 然后BootstrapApplicationListener捕捉到事件然后开始SpringApplicationBuilder.run
https://github.com/spring-cloud/spring-cloud-config/issues/836
java.lang.NoSuchMethodError: org.springframework.boot.builder.SpringApplicationBuilder.([Ljava/lang/Object;)V at org.springframework.cloud.bootstrap.BootstrapApplicationListener.bootstrapServiceContext(BootstrapApplicationListener.java:120) at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:84) at org.springframework.cloud.bootstrap.BootstrapApplicationListener.onApplicationEvent(BootstrapApplicationListener.java:62) at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:167) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139) at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:122) at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:72) at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:54) at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:360) at org.springframework.boot.SpringApplication.run(SpringApplication.java:328)
关于事件的一个一些知识:
https://www.logicbig.com/tutorials/spring-framework/spring-boot/application-listener.html
springboot启动的若干种方式, 其实吧, 平常启动的时候就包含了两种方式.
http://www.51gjie.com/javaweb/1042.html
@SpringBootApplication public class Application { //方式一 public static void main(String[] args) { SpringApplication.run(Application.class, args); } //方式二 public static void main(String[] args) { SpringApplication app = new SpringApplication(MySpringConfiguration.class); app.run(args); } //方式三 public static void main(String[] args) { new SpringApplicationBuilder() .sources(Parent.class) .child(Application.class) .run(args); } }
代码笔记:
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 }
SpringApplication.prepareEnvironment
1.listener.starting2.listener.environmentPrepared>>触发BootstrapApplicationListener,调用onApplicationEvent, 然后创建SpringApplicationBuilder builder = new SpringApplicationBuilder(), 又回到SpringApplication.run. 然后1,2(中间短路),3,4,5执行一遍.3.listener.contextPrepared>>context.refresh4.listener.started5.listener.running