深度剖析Spring Boot源碼,看完薪資敢要30K!

1 實例化SpringApplicationweb

SpringApplication.run(BootifulApplication.class, args);spring

​​​​​​​public static ConfigurableApplicationContext run(Class<?> primarySource,String... args) {return run(new Class<?>[] { primarySource }, args);}
​​​​​​​public static ConfigurableApplicationContext run(Class<?>[] primarySources,String[] args) {return new SpringApplication(primarySources).run(args);   //new SpringApplication}
​​​​​​​public SpringApplication(Class<?>... primarySources) {this(null, primarySources);}
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {//設置資源加載器爲nullthis.resourceLoader = resourceLoader;//斷言加載資源類不能爲nullAssert.notNull(primarySources, "PrimarySources must not be null");//將primarySources數組轉換爲List,最後放到LinkedHashSet集合中this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));//【1.1 推斷當前應用類型是否爲WEB】this.webApplicationType = WebApplicationType.deduceFromClasspath();//【1.2 設置應用上下文初始化器】setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));//【1.3 設置監聽器】setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));//【1.4 推斷應用的入口類】this.mainApplicationClass = deduceMainApplicationClass();}

1.1 推斷當前應用類型是否爲WEB

根據classpath下的內容推斷出應用的類型數組

this.webApplicationType = WebApplicationType.deduceFromClasspath();​​​​​​​session

static WebApplicationType deduceFromClasspath() {if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)&& !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {return WebApplicationType.REACTIVE;}for (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}return WebApplicationType.SERVLET;}

1.2 設置應用上下文初始化器

setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));app

  • ApplicationContextInitializerless

public interface ApplicationContextInitializer<C extends ConfigurableApplicationContext> {/*** Initialize the given application context.* @param applicationContext the application to configure*/void initialize(C applicationContext);}
  • getSpringFactoriesInstances(ApplicationContextInitializer.class)​​​​​​​spring-boot

​​​​​​​private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, new Class<?>[] {});}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) {//獲取當前上下文類加載器ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates//獲取ApplicationContextInitializer實例名稱而且去重Set<String> names = new LinkedHashSet<>(//進入loadFactoryNames方法而且找到loadSpringFactories---spring.factoriesSpringFactoriesLoader.loadFactoryNames(type, classLoader));//建立初始化器實例列表List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);//排序AnnotationAwareOrderComparator.sort(instances);return instances;}
  • setInitializers(...)post

初始化一個ApplicationContextInitializer​​​​​​​this

public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) {this.initializers = new ArrayList<>();this.initializers.addAll(initializers);}

1.3 設置監聽器

setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));spa

  • ApplicationListener

public interface ApplicationListener<E extends ApplicationEvent> extends EventListener {/*** Handle an application event.* @param event the event to respond to*/void onApplicationEvent(E event);}
  • getSpringFactoriesInstances(ApplicationListener.class)

​​​​​​​private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {return getSpringFactoriesInstances(type, new Class<?>[] {});}
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) {//獲取當前上下文類加載器ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicates//獲取ApplicationContextInitializer實例名稱而且去重Set<String> names = new LinkedHashSet<>(//進入loadFactoryNames方法而且找到loadSpringFactories---spring.factoriesSpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);//建立初始化器實例列表AnnotationAwareOrderComparator.sort(instances);//排序return instances;}
  • setListeners(...)

初始化一個ApplicationListener​​​​​​​

public void setListeners(Collection<? extends ApplicationListener<?>> listeners) {this.listeners = new ArrayList<>();this.listeners.addAll(listeners);}

 

1.4 推斷應用的入口類

 

this.mainApplicationClass = deduceMainApplicationClass();

 

private Class<?> deduceMainApplicationClass() {try {//構造一個運行時異常,遍歷異常棧中的方法名,獲取方法名爲main的棧幀,獲得入口類的名字再返回該類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;}

2 調用run方法

/*** Run the Spring application, creating and refreshing a new* {@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<>();//設置headless屬性configureHeadlessProperty();//【2.1 建立運行監聽器】SpringApplicationRunListeners listeners = getRunListeners(args);//發佈應用啓動事件listeners.starting();try {//初始化默認應用參數類ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);//【2.2 根據監聽器和應用參數類準備Spring環境】ConfigurableEnvironment environment = prepareEnvironment(listeners,applicationArguments);configureIgnoreBeanInfo(environment);//建立Banner打印類Banner printedBanner = printBanner(environment);//【2.3 建立應用上下文】context = createApplicationContext();//準備異常報告exceptionReporters = getSpringFactoriesInstances(SpringBootExceptionReporter.class,new Class[] { ConfigurableApplicationContext.class }, context);//【2.4 準備應用上下文】prepareContext(context, environment, listeners, applicationArguments,printedBanner);//【2.5 刷新應用上下文】refreshContext(context);//應用上下文後置處理刷新afterRefresh(context, applicationArguments);//中止計時類stopWatch.stop();//輸出日誌記錄執行主類名、時間信息if (this.logStartupInfo) {new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);}//發佈應用上下文啓動完成事件listeners.started(context);//【2.6 執行Runner運行器】callRunners(context, applicationArguments);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, listeners);throw new IllegalStateException(ex);}try {//發佈應用上下文就緒事件listeners.running(context);}catch (Throwable ex) {handleRunFailure(context, ex, exceptionReporters, null);throw new IllegalStateException(ex);}//返回應用上下文return context;}

2.1 建立運行監聽器

SpringApplicationRunListeners listeners = getRunListeners(args);​​​​​

private SpringApplicationRunListeners getRunListeners(String[] args) {Class<?>[] types = new Class<?>[] { SpringApplication.class, String[].class };return new SpringApplicationRunListeners(logger, getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args));}
  • SpringApplicationRunListener

org.springframework.boot:spring-boot/META-INF/spring.factories

  • getSpringFactoriesInstances(...)

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,Class<?>[] parameterTypes, Object... args) {ClassLoader classLoader = getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));List<T> instances = createSpringFactoriesInstances(type, parameterTypes,classLoader, args, names);AnnotationAwareOrderComparator.sort(instances);return instances;}
  • new SpringApplicationRunListeners(...)

SpringApplicationRunListeners(Log log,Collection<? extends SpringApplicationRunListener> listeners) {this.log = log;this.listeners = new ArrayList<>(listeners);}

2.2 根據監聽器和應用參數類準備Spring環境

ConfigurableEnvironment environment = prepareEnvironment(listeners,       applicationArguments);​​​​​​​

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments) {// Create and configure the environment//獲取應用環境(3種狀況)ConfigurableEnvironment environment = getOrCreateEnvironment();//配置應用環境configureEnvironment(environment, applicationArguments.getSourceArgs());listeners.environmentPrepared(environment);bindToSpringApplication(environment);if (!this.isCustomEnvironment) {environment = new EnvironmentConverter(getClassLoader()).convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);return environment;}

2.3 建立應用上下文

context = createApplicationContext();​​​​​​​

protected ConfigurableApplicationContext createApplicationContext() {Class<?> contextClass = this.applicationContextClass;if (contextClass == null) {try {switch (this.webApplicationType) {case SERVLET:contextClass = Class.forName(DEFAULT_SERVLET_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);}

 

2.4 準備應用上下文

prepareContext(context, environment, listeners, applicationArguments,         printedBanner);​​​​​​​

private void prepareContext(ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {//綁定環境到上下文context.setEnvironment(environment);//配置上下文的bean生成器和資源加載器postProcessApplicationContext(context);//爲上下文采用全部初始化器applyInitializers(context);//觸發監聽器的contextPrepared事件listeners.contextPrepared(context);//記錄啓動日誌if (this.logStartupInfo) {logStartupInfo(context.getParent() == null);logStartupProfileInfo(context);}// Add boot specific singleton beans//註冊兩個特殊的單例BeanConfigurableListableBeanFactory beanFactory = context.getBeanFactory();beanFactory.registerSingleton("springApplicationArguments", applicationArguments);if (printedBanner != null) {beanFactory.registerSingleton("springBootBanner", printedBanner);}if (beanFactory instanceof DefaultListableBeanFactory) {((DefaultListableBeanFactory) beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);}// Load the sources//加載全部資源Set<Object> sources = getAllSources();Assert.notEmpty(sources, "Sources must not be empty");load(context, sources.toArray(new Object[0]));//觸發監聽器的contextLoaded事件listeners.contextLoaded(context);}

 

2.5 刷新應用上下文

refreshContext(context);​​​​​​​

​​​​​​​private void refreshContext(ConfigurableApplicationContext context) {refresh(context);    //--->進入該方法if (this.registerShutdownHook) {try {context.registerShutdownHook();}catch (AccessControlException ex) {// Not allowed in some environments.}}}
​​​​​​​protected void refresh(ApplicationContext applicationContext) {Assert.isInstanceOf(AbstractApplicationContext.class, applicationContext);((AbstractApplicationContext) applicationContext).refresh();    //--->進入該方法}































public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.//context:啓動日期|設置context當前狀態|初始化環境|驗證必須prepareRefresh();// Tell the subclass to refresh the internal bean factory.//刷新內部bean工廠,即建立一個bean工廠(對BeanDefinition的定義、解析、處理和註冊)ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.//上面建立好了以後,還須要配置一些東西才能使用prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.//註冊WEB特性的scope(如request,session等)postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.//調用全部的bean工廠處理器對bean進行一些處理invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.//註冊用來攔截beanregisterBeanPostProcessors(beanFactory);// Initialize message source for this context.//主要用於國際化initMessageSource();// Initialize event multicaster for this context.//爲context初始化一個事件廣播器initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses./*在AbstractApplicationContext的子類中初始化其餘特殊的bean。其實就是初始化ThemeSource接口的實例。這個方法須要在全部單例bean初始化以前調用。*/onRefresh();// Check for listener beans and register them.//註冊應用監聽器registerListeners();// Instantiate all remaining (non-lazy-init) singletons.//完成對bean工廠初始化工做finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.//調用LifecycleProcessor的onRefresh()方法而且發佈事件finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}}}

 

2.6 執行Runner運行器

callRunners(context, applicationArguments);

執行全部ApplicationRunner和CommandLineRunner兩種運行器private void callRunners(ApplicationContext context, ApplicationArguments args) {

List<Object> runners = new ArrayList<>();runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());AnnotationAwareOrderComparator.sort(runners);for (Object runner : new LinkedHashSet<>(runners)) {if (runner instanceof ApplicationRunner) {callRunner((ApplicationRunner) runner, args);}if (runner instanceof CommandLineRunner) {callRunner((CommandLineRunner) runner, args);}}}
相關文章
相關標籤/搜索