Spring Boot 啟動源碼解析結合Spring Bean生命周期分析
- 2022 年 5 月 3 日
- 筆記
- Spring Boot
轉載請註明出處:
1.SpringBoot 源碼執行流程圖
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }
查看 SpringApplication 構造函數
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); // 獲取banner打印模式 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; // 默認賦值 applicationContextFactory 工廠對象 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)); // 根據類加載路徑推斷webApplicaitonType類型:SERVLET;REACTIVE this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 進行Spring的自動裝配,主要用來SpringFactoriesLoader類進行裝載工廠 this.bootstrappers = new ArrayList(this.getSpringFactoriesInstances(Bootstrapper.class)); this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); // 設置監聽器 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); this.mainApplicationClass = this.deduceMainApplicationClass(); }
查看run方法源碼
public ConfigurableApplicationContext run(String... args) { // 應用啟動計時器 StopWatch stopWatch = new StopWatch(); stopWatch.start(); DefaultBootstrapContext bootstrapContext = this.createBootstrapContext(); // 初始化應用上下文 ConfigurableApplicationContext context = null; this.configureHeadlessProperty(); // 獲取啟動監聽器 SpringApplicationRunListeners listeners = this.getRunListeners(args); //監聽器使用類似於生產-消費模式進行消息監聽 listeners.starting(bootstrapContext, this.mainApplicationClass); try { //構建應用參數 ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //準備應用環境 ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); this.configureIgnoreBeanInfo(environment); //打印banner Banner printedBanner = this.printBanner(environment); //創建ApplicationContext context = this.createApplicationContext(); context.setApplicationStartup(this.applicationStartup); //準備context this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner); //重點:刷新context:實現IOC容器啟動的整個過程 this.refreshContext(context); //後置工作 this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, listeners); throw new IllegalStateException(var10); } }
獲取啟動監聽器。實際上獲取的是一個EventPublishingRunListener對象,這個類能通過一個SimpleApplicationEventMulticaster對象廣播事件,用到了Executor多線程異步執行框架;
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) { // 根據前面推斷的web環境類型創建推Environment對象 ConfigurableEnvironment environment = this.getOrCreateEnvironment(); // 進行環境配置 this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs()); ConfigurationPropertySources.attach((Environment)environment); listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment); DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment); this.configureAdditionalProfiles((ConfigurableEnvironment)environment); this.bindToSpringApplication((ConfigurableEnvironment)environment); if (!this.isCustomEnvironment) { environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass()); } ConfigurationPropertySources.attach((Environment)environment); return (ConfigurableEnvironment)environment; }
prepareEnvironment 方法主要用來準備應用環境,進行property配置文件解析,profile 環境解析以及獲取系統屬性和系統環境等;
private ConfigurableEnvironment getOrCreateEnvironment() { if (this.environment != null) { return this.environment; } else { switch(this.webApplicationType) { case SERVLET: return new StandardServletEnvironment(); case REACTIVE: return new StandardReactiveWebEnvironment(); default: return new StandardEnvironment(); } } }
configureEnvironment() 源碼:
protected void configureEnvironment(ConfigurableEnvironment environment, String[] args) { if (this.addConversionService) { ConversionService conversionService = ApplicationConversionService.getSharedInstance(); environment.setConversionService((ConfigurableConversionService)conversionService); } // 配置屬性源 this.configurePropertySources(environment, args); //獲取激活的 profile this.configureProfiles(environment, args); }
createApplicationContext 方法源碼
protected ConfigurableApplicationContext createApplicationContext() { return this.applicationContextFactory.create(this.webApplicationType); }
進入 applicationContextFactory.create 方法的類中,存在一個根據webApplicationType獲取容器類型的變量方法如下:
@FunctionalInterface public interface ApplicationContextFactory { // 根據webApplicationType返回指定的容器實例 applicationContextFactoryApplicationContextFactory DEFAULT = (webApplicationType) -> { try { switch(webApplicationType) { case SERVLET: return new AnnotationConfigServletWebServerApplicationContext(); case REACTIVE: return new AnnotationConfigReactiveWebServerApplicationContext(); default: return new AnnotationConfigApplicationContext(); } } catch (Exception var2) { throw new IllegalStateException("Unable create a default ApplicationContext instance, you may need a custom ApplicationContextFactory", var2); } }; ConfigurableApplicationContext create(WebApplicationType webApplicationType); }
通過以上方式獲取到具體的ApplicationContext實例,並通過構造函數進行實例化,查看構造函數的過程:
構造方法源碼如下:
public AnnotationConfigApplicationContext() { // 啟動上面獲取的容器類型實例 StartupStep createAnnotatedBeanDefReader = this.getApplicationStartup().start("spring.context.annotated-bean-reader.create"); // 構建AnnotatedBeanDefinitionReader對象 this.reader = new AnnotatedBeanDefinitionReader(this); createAnnotatedBeanDefReader.end(); // 構建 ClassPathBeanDefinitionScanner對象 this.scanner = new ClassPathBeanDefinitionScanner(this); }
AnnotationConfigApplicationContext的父類GenericApplicationContext的默認構造器會構造一個DefaultListableBeanFactory 對象,這樣應用上下文持有一個bean factory的引用,大部分應用只需與應用上下文提供的接口打交道就是因為它對bean factory進行了一層封裝。至此,一個Spring容器已經構造出來了,但是目前這個容器還什麼都沒有,需要根據用戶的配置文件進行配置才能按照用戶邏輯進行工作。
prepareContext 方法源碼
private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context, ConfigurableEnvironment environment, SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments, Banner printedBanner) { // 使context持有應用環境的引用,同時將應用環境的引用賦給reader和scanner context.setEnvironment(environment); // 實現應用上下文的後置處理:主要是註冊BeanNameGenerator類型的bean並設置應用上下文的資源加載器和類加載器 this.postProcessApplicationContext(context); // 應用初始化器--添加監聽器、logger、warnning、以及spring啟動加解密等組件 this.applyInitializers(context); listeners.contextPrepared(context); bootstrapContext.close(context); if (this.logStartupInfo) { this.logStartupInfo(context.getParent() == null); this.logStartupProfileInfo(context); } ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 添加啟動相關的bean beanFactory.registerSingleton("springApplicationArguments", applicationArguments); // 註冊打印banner的bean if (printedBanner != null) { beanFactory.registerSingleton("springBootBanner", printedBanner); } // 註冊可定義重寫的bean if (beanFactory instanceof DefaultListableBeanFactory) { ((DefaultListableBeanFactory)beanFactory).setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding); } // 添加懶加載的bean工廠後置處理器 if (this.lazyInitialization) { context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor()); } // Load the sources Set<Object> sources = this.getAllSources(); Assert.notEmpty(sources, "Sources must not be empty"); // 重點:將source bean裝載到應用上下文 this.load(context, sources.toArray(new Object[0])); // 日誌配置 listeners.contextLoaded(context); }
通過 load 方法將所有的bean註冊到 容器中;該方法實現的調用鏈如下:
SpringApplication.load(ApplicationContext context, Object[] sources)--------> BeanDefinitionLoader.load()---->BeanDefinitionLoader.load(Object source)---> BeanDefinitionLoader.load(Class<?> source)----->AnnotatedBeanDefinitionReader.register(Class<?>... componentClasses)---> AnnotatedBeanDefinitionReader.registerBean(Class<?> beanClass)----> AnnotatedBeanDefinitionReader.doRegisterBean ---> BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
private final Map<String, BeanDefinition> beanDefinitionMap;
查看refreshContext 中 refresh 方法源碼
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. // 為應用上下文的刷新做準備--設置時間、記錄刷新日誌、初始化屬性源中的佔位符和驗證必要的屬性等 prepareRefresh(); // Tell the subclass to refresh the internal bean factory. // 使用CAS讓子類刷新內部的bean factory ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. // 準備在這個應用上下文中使用的bean factory prepareBeanFactory(beanFactory); try { // Allows post-processing of the bean factory in context subclasses. // bean factory 後置處理 postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. // 調用應用上下文中作為bean註冊的工廠處理器 invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. // 註冊攔截創建bean的bean處理器 registerBeanPostProcessors(beanFactory); // Initialize message source for this context. // 初始化消息源 initMessageSource(); // Initialize event multicaster for this context. // 初始化事件廣播 initApplicationEventMulticaster(); // Initialize other special beans in specific context subclasses. // 初始化特定上下文子類中的其它bean onRefresh(); // Check for listener beans and register them. // 註冊監聽器bean registerListeners(); // Instantiate all remaining (non-lazy-init) singletons. // 實例化所有的單例bean finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. // 發佈相應的事件 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(); } } }
AbstractApplicationContext#prepareRefresh() 源碼:
protected void prepareRefresh() { //記錄啟動時間 this.startupDate = System.currentTimeMillis(); //標誌位設置 this.closed.set(false); this.active.set(true); //日誌記錄一下 if (logger.isInfoEnabled()) { logger.info("Refreshing " + this); } // Initialize any placeholder property sources in the context environment // 初始化資源佔位符 initPropertySources(); // Validate that all properties marked as required are resolvable // see ConfigurablePropertyResolver#setRequiredProperties // 驗證所有必要的屬性能通過getProperty()解析,不能則拋出異常 getEnvironment().validateRequiredProperties(); // Allow for the collection of early ApplicationEvents, // to be published once the multicaster is available... this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>(); }
創建environment並加載System.properties()及System.getenv()到environment中
因為AbstractApplication沒有引用bean factory,只定義了刷新bean factory相關的方法,刷新bean factory的具體實現在子類的GenericApplicationContext#refreshBeanFactory()中實現,具體代碼和說明如下:
protected final void refreshBeanFactory() throws IllegalStateException { // 只支持刷新一次 if (!this.refreshed.compareAndSet(false, true)) { throw new IllegalStateException("GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once"); } // 設置序列號 this.beanFactory.setSerializationId(getId()); }
可以看到對bean factory的刷新實際上只是為其設置了一個序列號。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // Tell the internal bean factory to use the context's class loader etc. // 使用應用上下文的類加載器 beanFactory.setBeanClassLoader(getClassLoader()); // 設置bean表達式解析器 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 添加屬性編輯器註冊器 beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this,getEnvironment())); // Configure the bean factory with context callbacks. // 使用上下文回調函數配置bean factory beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); // BeanFactory interface not registered as resolvable type in a plain factory. // MessageSource registered (and found for autowiring) as a bean. // 註冊依賴 beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); // Register early post-processor for detecting inner beans as ApplicationListeners. // 添加一個用於探測實現了ApplicationListener接口的bean的後置處理器 beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); // Detect a LoadTimeWeaver and prepare for weaving, if found. // 探測LoadTimeWeaver並準備織入,與AOP相關 if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); // Set a temporary ClassLoader for type matching. beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // Register default environment beans. // 將默認環境作為bean註冊 if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment()); } if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties()); } if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) { beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment()); } }
addBeanPostProcessor()會添加一個ApplicationContextAwareProcessor處理器,這個類實現了BeanPostProcessor接口,同時由於應用上下文持有其它*Aware等的引用,因此在後面的代碼中忽略了這些依賴
該方法會掃描到指定包下標有註解的類,然後將其變成BeanDefinition對象,然後放到一個Spring的Map中,用於後面創建Spring bean的時候使用這個BeanDefinition
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // BeanFactory後置處理器的具體實現 PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime // (e.g. through an @Bean method registered by ConfigurationClassPostProcessor) if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } }
Spring委託PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors實現後置處理,它的具體實現很長,系統啟動時就註冊了幾個後置處理器,如SharedMetadataReaderFactoryContextInitializer,CachingMetadataReaderFactoryPostProcessor等。
代碼的執行思路是:先將後置處理器進行分類,分別是BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor,同時將BeanDefinitionRegistry註冊為一個BeanDefinition並調用註冊表後置處理器的相關方法(與註冊表相關);接着,按PriorityOrdered, Ordered和其它的順序調用手動添加(Spring Boot)的後置處理器。Spring Boot在之前註冊過一個ConfigurationClassPostProcessor後置處理器;
最終這個後置處理器會調用ConfigurationClassPostProcessor#processConfigBeanDefinitions()對配置類進行處理。在處理時需要創建 ConfigurationClassParser對象進行解析,同時會創建一個 ComponentScanAnnotationParser 對象,在這個類中會掃描獲取所有帶有註解的bean類;
ConfigurationClassPostProcessor#processConfigBeanDefinitions()具體的思路是先獲取所有的bean definition,並找出配置類對應的bean definition。接着對容器進行一下轉換並實例化一個ConfigurationClassParser配置類解析器對象parser,調用parser的parse()對配置類進行解析。ConfigurationClassParser#parse()的具體實現如下:
public void parse(Set<BeanDefinitionHolder> configCandidates) { this.deferredImportSelectors = new LinkedList<DeferredImportSelectorHolder>(); for (BeanDefinitionHolder holder : configCandidates) { BeanDefinition bd = holder.getBeanDefinition(); try { //如果bean是註解的,則解析註解---Spring Boot基於註解配置 if (bd instanceof AnnotatedBeanDefinition) { parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName()); } // 如果是抽象bean並且有bean類 else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) { parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName()); } else { // 普通解析 parse(bd.getBeanClassName(), holder.getBeanName()); } } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException( "Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex); } } // 處理延遲導入的選擇器 processDeferredImportSelectors(); }
對@ImportResource註解的處理
處理@Bean註解的方法不會註冊bean,只在配置類中註冊相應的方法。
處理超類
processDeferredImportSelectors()的具體實現:
private void processDeferredImportSelectors() { List<DeferredImportSelectorHolder> deferredImports = this.deferredImportSelectors; this.deferredImportSelectors = null; Collections.sort(deferredImports, DEFERRED_IMPORT_COMPARATOR); for (DeferredImportSelectorHolder deferredImport : deferredImports) { ConfigurationClass configClass = deferredImport.getConfigurationClass(); try { // 獲取importSelector---在自動配置源數據中刪除不符合要求或者無法實例化的對象 String[] imports = deferredImport.getImportSelector().selectImports(configClass.getMetadata()); //處理import---迭代處理,最終調用processConfigurationClass處理自動配置的類 processImports(configClass, asSourceClass(configClass), asSourceClasses(imports), false); } catch (BeanDefinitionStoreException ex) { throw ex; } catch (Throwable ex) { throw new BeanDefinitionStoreException("Failed to process import candidates for configuration class [" + configClass.getMetadata().getClassName() + "]", ex); } } }
至此,Spring Boot的自動配置基本完成
3.5.5 registerBeanPostProcessors()
根據實現了PropertyOrdered,Order接口,排序後註冊所有的BeanPostProcessor後置處理器,主要用於創建bean時,執行這些後置處理器的方法,這也是Spring 提供的擴展點,讓我們能夠插手Spring bean的創建過程。
完成所所有單例bean的創建和實例化,其方法調用鏈如下
AbstractApplicationContext.finishBeanFactoryInitialization(方法最後一行)-----〉 AbstractBeanFactory.getBean---->AbstractBeanFactory.doGetBean-------> AbstractAutowireCapableBeanFactory.createBean-------> 重點:AbstractAutowireCapableBeanFactory.doCreateBean(這個方法進行bean的生命周期)
在實例化Bean的過程中,會按照順序執行,如下:
resolveBeforeInstantiation會找到類型為InstantiationAwareBeanPostProcessor,且在Bean初始化前對Bean執行操作,實例化 —-》 AbstractAutowireCapableBeanFactory.doCreateBean() populateBean注入屬性initalizeBean方法調用擴展,順序如下:
1)如果Bean是BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,會執行者幾個的方法Aware的對應方法
2)先執行所有BeanPostProcessor.postProcessBeforeInitialization()
3) 反射調用init方法,如果Bean是InitializingBean,會先執行InitializingBean的afterPropertiesSet方法, 然後在執行自動以的init方法 、
4)調用所有BeanPostProcessor.applyBeanPostProcessorsAfterInitialization()方法 @PostConstruct標記的方法,是在BeanPostProcessor.postProcessBeforeInitialization() 調用時執行,也就是有一個BeanPostProcessor用於處理標記了該註解的方法(InitDestroyAnnotationBeanPostProcessor),定時器等註解,原理也是一樣的,在解析BeanDefinition時,會將這些註解都解析成BeanDefinition的一個屬性
可以簡述為以下九步
-
實例化bean對象(通過構造方法或者工廠方法)
-
設置對象屬性(setter等)(依賴注入)
-
如果Bean實現了BeanNameAware接口,工廠調用Bean的setBeanName()方法傳遞Bean的ID。(和下面的一條均屬於檢查Aware接口)
-
如果Bean實現了BeanFactoryAware接口,工廠調用setBeanFactory()方法傳入工廠自身
-
將Bean實例傳遞給Bean的前置處理器的postProcessBeforeInitialization(Object bean, String beanname)方法
-
調用Bean的初始化方法; Spring檢測對象如果實現InitializingBean這個接口,就會執行他的afterPropertiesSet()方法,定製初始化邏輯。以及進行@PostConstruct註解邏輯實現
-
將Bean實例傳遞給Bean的後置處理器的postProcessAfterInitialization(Object bean, String beanname)方法
-
使用Bean
-
容器關閉之前,調用Bean的銷毀方法
-