The
SpringApplication
class provides a convenient way to bootstrap a Spring application that is started from amain()
method. In many situations, you can delegate to the staticSpringApplication.run
method, as shown in the following example.java(SpringApplication類提供了一種便利的方式以便引導Spring應用從
#main
啓動,大多數狀況下,能夠經過靜態方法SpringApplication#run
代理啓動)web
SpringApplication
@EnableAutoConfiguration public class MyApplication { // ... Bean definitions public static void main(String[] args) throws Exception { SpringApplication.run(MyApplication.class, args); } }
SpringApplication
SpringApplication
API To Changepublic static void main(String[] args) { SpringApplication app = new SpringApplication(MySpringConfiguration.class); app.setBannerMode(Banner.Mode.OFF); app.run(args); }
SpringApplicationBuilder
API To Changenew SpringApplicationBuilder() .sources(Parent.class) .child(Application.class) .bannerMode(Banner.Mode.OFF) .run(args);
Java 配置類或XML上下文配置集合,用於Spring Boot BeanDefinitionLoader
讀取,而且將配置源解析加載爲Spring Bean 定義。spring
使用Spring 註解驅動中的Java配置類,也就是Spring 模式註解所標註的類,例如@Configuration
編程
package com.yi23.backend.springboot.bootstrap; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * {@link SpringApplication} 啓動引導類 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> * @see * @since */ @SpringBootApplication public class SpringApplicationBootstrap { public static void main(String[] args) { SpringApplication.run(SpringApplicationBootstrap.class,args); } }
用戶Spring 傳統配置驅動的XML文件bootstrap
... //設置Annotation配置源 Set<String> sources = new HashSet<>(); //A source can be: a class name, package name, or an XML resource location. sources.add(Yi23ApplicationConfiguration.class.getName()); springApplication.setSources(sources); ...
根據當前應用CLassPath中是否存在相關實現來推斷Web Application Type,包括:api
WebApplicationType.REACTIVE
WebApplicationType.SERVLET
WebApplicationType.NONE
參考:org.springframework.boot.SpringApplication#deduceWebApplicationType
springboot
private WebApplicationType deduceWebApplicationType() { if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null) && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className : WEB_ENVIRONMENT_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
跟住main線程的執行堆棧判斷當前實際的引導類app
參考:org.springframework.boot.SpringApplication#deduceMainApplicationClass
異步
private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
ApplicationContextInitializer
是應用上下文的加載器,利用Spring 工廠加載機制,實例化ApplicationContextInitializer
實現類,並實現對象集合排序ide
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); // Use names and ensure unique to protect against duplicates Set<String> names = new LinkedHashSet<>( SpringFactoriesLoader.loadFactoryNames(type, classLoader)); List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }
org.springframework.core.io.support.SpringFactoriesLoader
META-INF/spring.factories
org.springframework.core.annotation.AnnotationAwareOrderComparator#sort
package com.yi23.backend.springboot.context; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; /** * 自定義高優先級{@link ApplicationContextInitializer}初始化加載器 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> * @see * @since */ @Order(Ordered.HIGHEST_PRECEDENCE) public class HelloYi23ApplicationContextInitializer implements ApplicationContextInitializer { @Override public void initialize(ConfigurableApplicationContext applicationContext) { System.out.println("高優先級初始化加載class : " + applicationContext.getId()); } }
# Initializers org.springframework.context.ApplicationContextInitializer=\ com.yi23.backend.springboot.context.AfterHelloYi23ApplicationContextInitializer,\ com.yi23.backend.springboot.context.HelloYi23ApplicationContextInitializer
利用Spring 工廠加載機制,實例化ApplicationLisener
實現類,並實現對象集合排序
package com.yi23.backend.springboot.event.listener; import org.springframework.context.ApplicationListener; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.Ordered; /** * hello yi23 {@link ApplicationListener} 監聽 {@link ContextRefreshedEvent}事件 * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> * @see * @since */ public class HelloYi23ApplicationListener implements ApplicationListener<ContextRefreshedEvent>,Ordered { @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.printf("上下文內容id:%s,timestamp:%s.\r\n", event.getApplicationContext().getId(), event.getTimestamp()); } @Override public int getOrder() { return Ordered.HIGHEST_PRECEDENCE; } }
SpringApplication
Run Listenerorg.springframework.boot.SpringApplicationRunListeners
利用工廠加載機制,讀取SpringApplicationRunListener
對象集合,並封裝到組合對象SpringApplicationRunListeners
private SpringApplicationRunListeners getRunListeners(String[] args) { Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class }; return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances( SpringApplicationRunListener.class, types, this, args)); }
SpringApplication
Run ListenersSpringApplicationRunListener
監聽多個運行狀態方法
監聽方法 | 階段說明 | Springboot 起始版本 |
---|---|---|
starting |
Spring 應用剛剛啓動 | 1.0 |
environmentPrepared(ConfigurableEnvironment) |
ConfigurableEnvironment 準確以後,容許將其修改 |
1.0 |
contextPrepared(ConfigurableApplicationContext) |
ConfigurableApplicationContext 準備以後,容許將其修改 |
1.0 |
contextLoaded(ConfigurableApplicationContext) |
ConfigurableApplicationContext 已加載,但未啓動 |
1.0 |
started(ConfigurableApplicationContext) |
ConfigurableApplicationContext 已啓動,當前Spring Bean已初始化完成 |
2.0.0 |
running(ConfigurableApplicationContext) |
Spring Application 正在運行 | 2.0.0 |
failed(ConfigurableApplicationContex,Throwable) |
Spring Application運行失敗 | 2.0.0 |
SpringBoot 經過SpringApplicationRunListener
的實現類EventPublishingRunListener
,利用Spring Framework事件API,廣播Spring Boot 事件
ApplicationEvent
ApplicationContextEvent
ApplicationListener
@EventListener
ApplicationEventMulticaster
SimpleApplicationEventMulticaster
EventPublishingRunListener
relationship of Monitor‘s Method & Spring Boot Events監聽方法 | Spring Boot 事件 | Spring boot 起始版本 |
---|---|---|
starting |
ApplicationStartingEvent |
1.5.0 |
environmentPrepared(ConfigurableEnvironment) |
ApplicationEnvironmentPreparedEvent |
1.0 |
contextPrepared(ConfigurableApplicationContext) |
||
contextLoaded(ConfigurableApplicationContext) |
ApplicationPreparedEvent |
1.0 |
started(ConfigurableApplicationContext) |
ApplicationStartedEvent |
2.0.0 |
running(ConfigurableApplicationContext) |
ApplicationReadyEvent |
1.3.0 |
failed(ConfigurableApplicationContex,Throwable) |
ApplicationFailedEvent |
1.0 |
ConfigFileApplicationListener
Orderpackage com.yi23.backend.springboot.event.listener; import org.springframework.boot.context.config.ConfigFileApplicationListener; import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; import org.springframework.boot.context.event.ApplicationPreparedEvent; import org.springframework.context.ApplicationEvent; import org.springframework.context.event.SmartApplicationListener; import org.springframework.core.Ordered; import org.springframework.core.env.Environment; /** * Before {@link ConfigFileApplicationListener} * * @author <a href="mailto:magicianisaac@gmail.com">Isaac.Zhang</a> * @see * @since */ public class BeforeConfigFileApplicationListener implements SmartApplicationListener, Ordered { @Override public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) { return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType) || ApplicationPreparedEvent.class.isAssignableFrom(eventType); } @Override public boolean supportsSourceType(Class<?> aClass) { return true; } @Override public void onApplicationEvent(ApplicationEvent event) { if (event instanceof ApplicationEnvironmentPreparedEvent) { ApplicationEnvironmentPreparedEvent environmentPreparedEvent = (ApplicationEnvironmentPreparedEvent) event; Environment environment = environmentPreparedEvent.getEnvironment(); System.out.println("environment.getProperty(\"name\"): " + environment.getProperty("name")); } if (event instanceof ApplicationPreparedEvent) { } } @Override public int getOrder() { //比 ConfigFileApplicationListener 優先級高 return ConfigFileApplicationListener.DEFAULT_ORDER - 1; } }
ConfigurableApplicationContext
)根據前面提到的Prepared 階段推斷出的Web 應用類型對應的ConfigurableApplicationContext
實例:
AnnotationConfigReactiveWebServerApplicationContext
AnnotationConfigServletWebServerApplicationContext
AnnotationConfigApplicationContext
/** * Strategy method used to create the {@link ApplicationContext}. By default this * method will respect any explicitly set application context or application context * class before falling back to a suitable default. * @return the application context (not yet refreshed) * @see #setApplicationContextClass(Class) */ protected ConfigurableApplicationContext createApplicationContext() { Class<?> contextClass = this.applicationContextClass; if (contextClass == null) { try { switch (this.webApplicationType) { case SERVLET: contextClass = Class.forName(DEFAULT_WEB_CONTEXT_CLASS); break; case REACTIVE: contextClass = Class.forName(DEFAULT_REACTIVE_WEB_CONTEXT_CLASS); break; default: contextClass = Class.forName(DEFAULT_CONTEXT_CLASS); } } catch (ClassNotFoundException ex) { throw new IllegalStateException( "Unable create a default ApplicationContext, " + "please specify an ApplicationContextClass", ex); } } return (ConfigurableApplicationContext) BeanUtils.instantiateClass(contextClass); }
根據Prepead 階段推斷的Web應用類型建立對應的 ConfigurableEnvironment
StandardServletEnvironment
StandardEnvironment
StandardEnvironment
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } if (this.webApplicationType == WebApplicationType.SERVLET) { return new StandardServletEnvironment(); } return new StandardEnvironment(); }