Spring Boot Application Internally Works

Spring Boot Application Internally Works

Steps

  • 初始化階段
    • new SpringApplication() 調用建構子,建立一個 Spring 應用程式實例。 在建構方法中完成啟動環境的初始化作業,並設置初始參數。
      • 判定 Spring Application 類型 ==> Web Servlet / Reactive Servlet
  • SpringApplication.run() 調用 run(),所有的啟動工作都在此方法中完成。
    • 準備階段 (Environment Setup)
    • 發布事件
    • 建立 Context 與 Bean
    • 刷新 Context
    • 最後階段處理

初始化

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {  
    this.sources = new LinkedHashSet();  
    this.bannerMode = Mode.CONSOLE;  
    this.logStartupInfo = true;  
    this.addCommandLineProperties = true;  
    this.addConversionService = true;  
    this.headless = true;  
    this.registerShutdownHook = true;  
    this.additionalProfiles = Collections.emptySet();  
    this.isCustomEnvironment = false;  
    this.lazyInitialization = false;  
    this.applicationContextFactory = ApplicationContextFactory.DEFAULT;  
    this.applicationStartup = ApplicationStartup.DEFAULT;  
    this.resourceLoader = resourceLoader;  
    Assert.notNull(primarySources, "PrimarySources must not be null");  
    this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));  
    this.webApplicationType = WebApplicationType.deduceFromClasspath();  
    this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));  
    this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));  
    this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));  
    this.mainApplicationClass = this.deduceMainApplicationClass();  
}

@SpringBootApplication 註解內容

@SpringBootConfiguration  
@EnableAutoConfiguration  
@ComponentScan(  
    excludeFilters = {@Filter(  
    type = FilterType.CUSTOM,  
    classes = {TypeExcludeFilter.class}  
), @Filter(  
    type = FilterType.CUSTOM,  
    classes = {AutoConfigurationExcludeFilter.class}  
)}  
)
  • @SpringBootConfiguration ==> @Configuration 將目前的類別註冊為 Spring IoC 的配置類別。

run()

SpringApplicationRunListeners

class SpringApplicationRunListeners {

	private final Log log;

	private final List<SpringApplicationRunListener> listeners;

	private final ApplicationStartup applicationStartup;

	SpringApplicationRunListeners(Log log, List<SpringApplicationRunListener> listeners,
			ApplicationStartup applicationStartup) {
		this.log = log;
		this.listeners = List.copyOf(listeners);
		this.applicationStartup = applicationStartup;
	}

	void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
		doWithListeners("spring.boot.application.starting", (listener) -> listener.starting(bootstrapContext),
				(step) -> {
					if (mainApplicationClass != null) {
						step.tag("mainApplicationClass", mainApplicationClass.getName());
					}
				});
	}

	void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
		doWithListeners("spring.boot.application.environment-prepared",
				(listener) -> listener.environmentPrepared(bootstrapContext, environment));
	}

	void contextPrepared(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-prepared", (listener) -> listener.contextPrepared(context));
	}

	void contextLoaded(ConfigurableApplicationContext context) {
		doWithListeners("spring.boot.application.context-loaded", (listener) -> listener.contextLoaded(context));
	}

	void started(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.started", (listener) -> listener.started(context, timeTaken));
	}

	void ready(ConfigurableApplicationContext context, Duration timeTaken) {
		doWithListeners("spring.boot.application.ready", (listener) -> listener.ready(context, timeTaken));
	}

	void failed(ConfigurableApplicationContext context, Throwable exception) {
		doWithListeners("spring.boot.application.failed",
				(listener) -> callFailedListener(listener, context, exception), (step) -> {
					step.tag("exception", exception.getClass().toString());
					step.tag("message", exception.getMessage());
				});
	}

	private void callFailedListener(SpringApplicationRunListener listener, ConfigurableApplicationContext context,
			Throwable exception) {
		try {
			listener.failed(context, exception);
		}
		catch (Throwable ex) {
			if (exception == null) {
				ReflectionUtils.rethrowRuntimeException(ex);
			}
			if (this.log.isDebugEnabled()) {
				this.log.error("Error handling failed", ex);
			}
			else {
				String message = ex.getMessage();
				message = (message != null) ? message : "no error message";
				this.log.warn("Error handling failed (" + message + ")");
			}
		}
	}

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction) {
		doWithListeners(stepName, listenerAction, null);
	}

	private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction,
			Consumer<StartupStep> stepAction) {
		StartupStep step = this.applicationStartup.start(stepName);
		this.listeners.forEach(listenerAction);
		if (stepAction != null) {
			stepAction.accept(step);
		}
		step.end();
	}
}