AnnotationConfigApplicationContext構造方法中三個方法中第一個方法上面分析過了,現在我們來看下第二個方法:register(componentClasses)。
之前使用XML方式:new ClassPathXmlApplicationContext("classpath:spring.xml");,構造方法中需要指定xml配置文件路徑,然后就可以解析xml文件中、等配置進行IoC啟動初始化。同理,使用注解方式也需要給Context指定一個起始配置源頭,使用配置類代替xml配置文件,然后根據這個起始配置類一步步的解析下去。
(相關資料圖)
@Configuration@ComponentScan(basePackageClasses = {TestConfig.class})@Import(TestService03.class)public class TestConfig { @Bean public TestService01 testService01(){ return new TestService01(); }}通過這個配置類,Spring就可以解析@ComponentScan、@Import、@Bean等這些注解,實現Bean注入到IoC容器中。@Configuration注解定義的配置類就相當于之前xml配置文件,不過由于現在Spring主流都推薦注解方式,xml方案使用的概率會越來越低。
跟蹤register(componentClasses)方法,核心邏輯在:AnnotatedBeanDefinitionReader#doRegisterBean:
private void doRegisterBean(Class beanClass, @Nullable String name, @Nullable Class extends Annotation>[] qualifiers, @Nullable Supplier supplier, @Nullable BeanDefinitionCustomizer[] customizers) { //先把此實體類型轉換為一個BeanDefinition AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass); /** * abd.getMetadata()元數據包括注解信息、是否內部類、類Class基本信息等等 * 此處由conditionEvaluator#shouldSkip去過濾,此Class是否是配置類 * 大體邏輯為:必須有@Configuration修飾,然后解析一些Condition注解,看是否排除~ */ if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) { return; } abd.setInstanceSupplier(supplier); // 解析Scope ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd); abd.setScope(scopeMetadata.getScopeName()); // 得到Bean的名稱 一般為首字母小寫(此處為AnnotationBeanNameGenerator) String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry)); // 設定一些注解默認值,如lazy、Primary等等 AnnotationConfigUtils.processCommonDefinitionAnnotations(abd); if (qualifiers != null) {// 解析qualifiers,若有此注解 則primary都成為true了 for (Class extends Annotation> qualifier : qualifiers) { if (Primary.class == qualifier) { abd.setPrimary(true); } else if (Lazy.class == qualifier) { abd.setLazyInit(true); } else { abd.addQualifier(new AutowireCandidateQualifier(qualifier)); } } } if (customizers != null) {// 自定義定制信息(一般都不需要) for (BeanDefinitionCustomizer customizer : customizers) { customizer.customize(abd); } } // 下面解析Scope是否需要代理,最后把這個Bean注冊進去 BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName); definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry); BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);} 就是將傳入的配置類解析成解析成BeanDefinition,注冊到IoC容器中,后續(xù)ConfigurationClassPostProcessor這個BeanFactory后置處理器在IoC開始真正初始化時,可以獲取到這些配置類的BeanDefinition集合,啟動解析。
前面分析了AnnotationConfigApplicationContext構造方法中前兩個,這兩個方法基本都是IoC啟動的前戲:為IoC容器的啟動做熱身準備;真正的IoC容器啟動初始化流程是在refresh()方法中,這是了解IoC容器啟動流程最關鍵、核心的一個方法。
refresh方法定義在AbstractApplicationContext,采用模板模式,定義好IoC啟動的流程以及每個步驟的作用,并提供基礎實現,其它子類可以重寫進行擴展。
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { //Context進行刷新前的準備工作 prepareRefresh(); // 創(chuàng)建并初始化 BeanFactory,這步會將BeanDefinition載入到BeanFactory中 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); /** * 填充BeanFactory功能 * 上面獲取獲取的 BeanFactory其實還不能投入生產,因為還少配置了一些東西,比如 context的 ClassLoader 和 后置處理器等等。 */ prepareBeanFactory(beanFactory); try { /** * 默認空實現,留給子類擴展使用 * 可以參照:AbstractRefreshableWebApplicationContext#postProcessBeanFactory() */ postProcessBeanFactory(beanFactory); /** * 調用BeanFactory后置處理器(包括BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor) */ invokeBeanFactoryPostProcessors(beanFactory); registerBeanPostProcessors(beanFactory); //初始化消息源 initMessageSource(); //初始化應用上下文事件廣播器 initApplicationEventMulticaster(); //初始化其它特殊的Bean,由具體子類實現 onRefresh(); //注冊事件監(jiān)聽器 registerListeners(); //初始化所有單實例Bean,使用懶加載模式的Bean除外 finishBeanFactoryInitialization(beanFactory); //完成刷新并發(fā)布容器刷新事件 finishRefresh(); } catch (BeansException ex) { ...//省略 } finally { resetCommonCaches(); } }}下面就來分析下每個方法作用,以了解IoC容器的啟動流程。
prepareRefresh從方法名稱可以看出,該方法主要在refresh執(zhí)行前進行一些簡單的準備工作,如設置Context的啟動時間、狀態(tài),以及系統(tǒng)屬性相關擴展。
/** * 初始化上下文環(huán)境,對系統(tǒng)的環(huán)境變量或者系統(tǒng)屬性進行準備和校驗,如環(huán)境變量中必須設置某個值才能運行,否則不能運行,這個時候可以在這里加這個校驗,重寫initPropertySources方法就好了 * * 該方法主要是做一些準備工作,如: * 1、設置 context 啟動時間 * 2、設置 context 的當前狀態(tài) * 3、初始化 context environment 中占位符 * 4、對屬性進行必要的驗證 */ protected void prepareRefresh() { //設置啟動時間 this.startupDate = System.currentTimeMillis(); //設置context當前狀態(tài) this.closed.set(false);//標志context狀態(tài):未關閉 this.active.set(true);//標志context狀態(tài):活躍中 /** * 初始化context environment(上下文環(huán)境)中屬性源信息,默認這里是空實現,什么都沒做,這里主要提供給子類擴展,采用模板設計模式 * 比如非web環(huán)境下,context environment是StandardEnvironment類型,只會在創(chuàng)建時初始化兩類屬性源:systemEnvironment(系統(tǒng)環(huán)境變量) * 和systemProperties(應用環(huán)境變量),通過@PropertySource注解等方式配置這時是還沒有加載的 * * * 該方法主要有兩個常見擴展: * 1、可以在該類中擴展PropertySource來源,如:getEnvironment().getPropertySources().addXXX(PropertySource ps),可以參見GenericWebApplicationContext#initPropertySources() * 2、可以在方法中添加必要屬性驗證,一些屬性對于應用來說是必要的,缺失則會影響系統(tǒng)的正常邏輯, * 如:getEnvironment().setRequiredProperties("DB_IP"),下一步就會從context environment上驗證是否存在該屬性,如果沒有則會拋出異常并退出Spring應用 */ initPropertySources(); /** * 對屬性必要性進行校驗,邏輯參見:AbstractPropertyResolver#validateRequiredProperties */ getEnvironment().validateRequiredProperties(); //早期事件監(jiān)聽器集合如果為空,就新建一個;如果不為空,就先清空事件監(jiān)聽器集合,然后將早期事件監(jiān)聽器整體放入事件監(jiān)聽器集合。 if (this.earlyApplicationListeners == null) { //默認情況下,earlyApplicationListeners為null this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners); } else { this.applicationListeners.clear(); this.applicationListeners.addAll(this.earlyApplicationListeners); } //保存容器中的一些早期事件,待事件派發(fā)器multicaster初始化完成后進行事件發(fā)布 this.earlyApplicationEvents = new LinkedHashSet<>();}這里主要注意下initPropertySources()和getEnvironment().validateRequiredProperties()這兩句代碼。PropertySource在Spring中代表一組變量,即類似對應于一個配置文件,比如@PropertySource("test01.properties")這個常用的注解就是將配置文件解析成一個PropertySource對象。
initPropertySources()方法主要用于擴展配置來源,比如可以從網絡、物理文件、數據庫等加載配置信息。StandardEnvironment在創(chuàng)建時,會自動將系統(tǒng)變量System.getProperties()和應用變量System.getenv()加載進來,所以initPropertySources默認只提供的是空實現,主要用于子類擴展使用。
1、可以在該類中擴展
initPropertySources方法主要有兩個常見擴展場景:
PropertySource來源,如:getEnvironment().getPropertySources().addXXX(PropertySource ps),可以參見GenericWebApplicationContext#initPropertySources()2、可以在方法中添加必要屬性驗證,一些屬性對于應用來說是必要的,缺失則會影響系統(tǒng)的正常邏輯,如:getEnvironment().setRequiredProperties("DB_IP"),下一步就會從context environment上驗證是否存在該屬性,如果沒有則會拋出異常并退出Spring應用getEnvironment().validateRequiredProperties()這句主要是對setRequiredProperties()方法設置的屬性進行必要性檢查,如果某個必要屬性環(huán)境中不存在,則拋出異常退出應用。
BeanFactory才是Spring中基本的IoC容器,ApplicationContext其實內部包裝了一個BeanFactory,并對其進行了增強,使其更智能、更好用。ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();這句主要意思是:通知Context,我要開始使用IoC容器進行初始化工作了,請?zhí)峁┙o我一個BeanFactory容器。這個方法比較簡單,基本沒有需要擴展的,就不再仔細研究。
上面獲取獲取的BeanFactory容器其實還不能投入生產,因為還缺少一些配置信息,這里主要向BeanFactory填充一些必要的配置。
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 設置beanFactory的classLoader beanFactory.setBeanClassLoader(getClassLoader()); // 設置beanFactory的表達式語言處理器,Spring3開始增加了對語言表達式的支持,默認可以使用#{bean.xxx}的形式來調用相關屬性值 beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader())); // 為beanFactory增加一個默認的propertyEditor beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment())); // 添加一個ApplicationContextAwareProcessor類型的Bean后置處理器,該后置處理器用于處理*Aware接口的依賴注入 beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this)); /** * 自動裝配時如下接口中setter方法的依賴注入會被忽略 * 如:EnvironmentAware#setEnvironment()該setter不能用于自動裝配時依賴注入方法, * 因為這些*Aware接口統(tǒng)一采用ApplicationContextAwareProcessor這個Bean后置處理器進行依賴注入 */ beanFactory.ignoreDependencyInterface(EnvironmentAware.class); beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class); beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class); beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class); beanFactory.ignoreDependencyInterface(MessageSourceAware.class); beanFactory.ignoreDependencyInterface(ApplicationContextAware.class); /** * 設置幾個自動裝配的特殊規(guī)則 * DefaultListableBeanFactory#findAutowireCandidates(DependencyDescriptor ds)在查找依賴注入值時: * 1、首先會從resolvableDependencies容器中查找,如果有直接返回找到的bean進行依賴注入; * 2、如果沒有,再從IoC容器中查找 * 所以,resolvableDependencies容器可以看成對常規(guī)IoC的一種擴充 */ beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory); beanFactory.registerResolvableDependency(ResourceLoader.class, this); beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this); beanFactory.registerResolvableDependency(ApplicationContext.class, this); /** * 添加一個ApplicationListenerDetector類型的Bean后置處理器,將類型是ApplicationListener的bean添加到事件廣播器,以便觸發(fā)事件時被調用 */ beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this)); /** * 增加對AspectJ的支持 * 檢查容器中是否包含名稱為loadTimeWeaver的bean,實際上是增加Aspectj的支持 * AspectJ采用編譯期織入、類加載期織入兩種方式進行切面的織入 * 類加載期織入簡稱為LTW(Load Time Weaving),通過特殊的類加載器來代理JVM默認的類加載器實現 */ if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { // 添加BEAN后置處理器:LoadTimeWeaverAwareProcessor // 在BEAN初始化之前檢查BEAN是否實現了LoadTimeWeaverAware接口, // 如果是,則進行加載時織入,即靜態(tài)代理。 beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); } // 注冊默認的系統(tǒng)環(huán)境bean // 這樣應用程序中通過:getBean("environment")、getBean("systemProperties")、getBean("systemEnvironment") 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()); }}上面邏輯大致可以總結:
給BeanFactory設置ClassLoader、EL表達式解析器等;添加一個BeanPostProcessor:ApplicationContextAwareProcessor,這個主要完成對*Aware接口功能支持,實現的核心邏輯見下:判斷是否實現了XXXAware接口,如果實現則調用對應的setter方法注入依賴值。private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); }}ignoreDependencyInterface方法設置一些忽略接口:自動裝配時如遇到忽略接口中setter方法的依賴注入會被忽略,因為這些*Aware接口統(tǒng)一采用ApplicationContextAwareProcessor這個后置處理器進行依賴注入。registerResolvableDependency方法設置一些特殊的內置對象,DefaultListableBeanFactory#findAutowireCandidates(DependencyDescriptor ds)在查找依賴注入值時:a、首先會從resolvableDependencies容器中查找,如果有直接返回找到的bean進行依賴注入;b、如果沒有,再從IoC容器中查找。因此,resolvableDependencies容器可以看出是對IoC容器的一種擴充,該容器中的對象是沒有經過Spring一系列容器創(chuàng)建流程,而是直接new方式創(chuàng)建。再添加一個Bean后置處理器:ApplicationListenerDetector,將系統(tǒng)中實現ApplicationListener接口的對象都統(tǒng)一存儲到Set> applicationListeners 中,采用了典型的事件監(jiān)聽/發(fā)布模式;LTW功能判斷,LTW全稱LoadTimeWeaver,即:加載時織入。AOP和OOP一樣,是一種編程思想,按照織入時機可以分為三類:編譯時織入、類加載時織入和運行時織入。AspectJ實現就是編譯時織入,采用的是一種特殊的編譯器;Spring AOP采用的動態(tài)代理實現(jdk動態(tài)代理、cglib動態(tài)代理),這是一種運行時織入,缺點就是必須納入IoC管理的Bean才能被代理;而LTW是類加載時織入,借助于JVM提供的Instrumentation技術,在JDK加載類時織入增強邏輯。注冊三個環(huán)境變量相關
Instrumentation是在JVM加載Class時進行代碼織入,對現有應用沒有任何的侵入,APM Agent開發(fā)中就比較常用該技術。
Bean到容器中,這樣應用中可以依賴注入到程序中進行使用;beanFactory.registerSingleton方式把對象存儲到singletonObjects集合中,它類似于一個緩存,從IoC獲取Bean時,首先會通過getSingleton方法從緩存拿,如果緩存拿不到再去獲取對應的BeanDefinition進行實例化,然后實例化對象放到singletonObjects集合中。postProcessBeanFactory(beanFactory)默認是空實現,主要是留給子類進行擴展,從名稱上看該方法主要用于添加BeanFactoryPostProcessor,AnnotationConfigApplicationContext已經在前面注冊了一個ConfigurationClassPostProcessor,主要用于完成對Spring配置類的處理,其它子類可以重新這個方法增加其它BeanFactoryPostProcessor對象,實現功能擴充。
前面巴拉巴拉一大堆,基本還是各種配置、填充工作,這一步就到了IoC容器開始真正干活的階段了。invokeBeanFactoryPostProcessors(beanFactory)方法主要就是完成對所有注冊進來的BeanFactory后置處理器執(zhí)行調用,包括BeanFactoryPostProcessor及其子類BeanDefinitionRegistryPostProcessor。這里就會有個前面提到的Spring中非常重要的一個類:ConfigurationClassPostProcessor開始被執(zhí)行,它執(zhí)行完成后,所有需要Spring管理的Bean都會被解析成BeanDefinition注冊進來。由于ConfigurationClassPostProcessor非常的復雜,后續(xù)會單獨分析這個類,這篇主要是對IoC啟動的流程有個大致的、直觀印象。執(zhí)行完這步,你只需要簡單知道@Configuration、@Bean、@Import、@ComponentScan、@Component等等相關配置注解會被處理,相關的Bean也被解析成BeanDefinition注冊進來即可。
protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); // LTW探測 if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) { beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory)); beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader())); }}getBeanFactoryPostProcessors()獲取到ApplicationContext.beanFactoryPostProcessors集合中存儲的BeanFactoryPostProcessor,通過addBeanFactoryPostProcessor()方法添加的,這里集合為空,因為從前面代碼看并沒有調用過該方法。
這里核心在invokeBeanFactoryPostProcessors()方法。首先,看下if (beanFactory instanceof BeanDefinitionRegistry)判斷,如果容器不是BeanDefinitionRegistry類型或子類,則表示當前容器不能向容器注冊Bean,所以只需要執(zhí)行BeanFactoryPostProcessor類型后置處理器即可,BeanDefinitionRegistryPostProcessor后置處理器不需要執(zhí)行,因為該后置處理器主要是用來向IoC容器中注冊Bean,大部分我們使用的容器都是BeanDefinitionRegistry類型,這樣才能把我們業(yè)務Bean納入Spring管理,所以基本上都是走if語句塊。
//判斷我們的beanFactory是否實現了BeanDefinitionRegistryif (beanFactory instanceof BeanDefinitionRegistry) { ...//省略}else { invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);}invokeBeanFactoryPostProcessors方法核心就是執(zhí)行BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor,但是涉及到執(zhí)行優(yōu)先級、執(zhí)行后可能會產生新PostProcessor等,所以這里的代碼看起來比較長,總結下執(zhí)行邏輯大致如下:
1、先執(zhí)行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法,其中BeanDefinitionRegistryPostProcessor執(zhí)行優(yōu)先級如下:a、addBeanFactoryPostProcessor()傳入到優(yōu)先級最高,因為不需要實例化,直接可以獲取到對象進行執(zhí)行;b、然后從IoC容器中獲取PriorityOrdered接口的BeanDefinitionRegistryPostProcessor,實例化并排序后執(zhí)行postProcessBeanDefinitionRegistry方法c、然后從IoC容器中獲取Ordered接口的BeanDefinitionRegistryPostProcessor,實例化并排序后執(zhí)行postProcessBeanDefinitionRegistry方法d、然后從IoC容器中獲取剩余的BeanDefinitionRegistryPostProcessor,實例化后執(zhí)行postProcessBeanDefinitionRegistry方法;注意這個處理步驟存在一個循環(huán),主要是存在執(zhí)行前面的BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry方法時,存在可能會向IoC容器中注冊新的BeanDefinitionRegistryPostProcessor,通過循環(huán)保證都會被執(zhí)行;2、然后執(zhí)行BeanDefinitionRegistryPostProcessor#postProcessBeanFactory方法,執(zhí)行順序參照步驟1中執(zhí)行順序;3、最后才會執(zhí)行BeanFactoryPostProcessor#postProcessBeanFactory,執(zhí)行優(yōu)先級和BeanDefinitionRegistryPostProcessor一致:a、addBeanFactoryPostProcessor()傳入到優(yōu)先級最高,因為不需要實例化,直接可以獲取到對象進行執(zhí)行;b、然后從IoC容器中獲取PriorityOrdered接口的BeanFactoryPostProcessor,實例化并排序后執(zhí)行postProcessBeanFactory方法c、然后從IoC容器中獲取Ordered接口的BeanFactoryPostProcessor,實例化并排序后執(zhí)行postProcessBeanFactory方法d、然后從IoC容器中獲取剩余的BeanFactoryPostProcessor,實例化后執(zhí)行postProcessBeanFactory方法這里有個細節(jié),在執(zhí)行
BeanFactoryPostProcessor#postProcessBeanFactory方法是沒有循環(huán),而執(zhí)行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry中存在一個循環(huán),主要是因為BeanFactoryPostProcessor#postProcessBeanFactory方法是不會像IoC中注冊Bean,這樣執(zhí)行過程中就不會產生新的BeanFactoryPostProcessor。
上面寫了一大堆,概況下就是:
1、方法優(yōu)先級:BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry> BeanDefinitionRegistryPostProcessor#postProcessBeanFactory> BeanFactoryPostProcessor#postProcessBeanFactory;
2、同方法優(yōu)先級:addBeanFactoryPostProcessor> PriorityOrdered> Ordered> 非排序
registerBeanPostProcessors方法主要是將BeanDefinition對應的BeanPostProcessor實例化并通過beanFactory.addBeanPostProcessor()方法注冊進來。前面分析過AnnotationConfigUtils.registerAnnotationConfigProcessors會向容器注冊幾個Spring內置的BeanPostProcessor,這步主要是將應用中引入的BeanPostProcessor注冊進來。
上步invokeBeanFactoryPostProcessors執(zhí)行完成后,Spring會將所有的Bean解析成BeanDefinition注冊到容器中,其中就可能包含BeanPostProcessor的BeanDefinition信息,這個方法就是把這些BeanPostProcessor對應的BeanDefinition通過getBean方式實例化,并通過addBeanPostProcessor()注冊進來,這樣這些BeanPostProcessor才能起作用。
這個方法代碼巴拉巴拉一大堆,流出總結起來還是很清晰,這里就不再上代碼:
獲取實現PriorityOrdered接口的BeanPostProcessor,然后通過getBean()方法實例化,排序后注冊到容器中;獲取實現Ordered接口的BeanPostProcessor,然后通過getBean()方法實例化,排序后注冊到容器中;獲取常規(guī)沒有實現PriorityOrdered和Ordered接口BeanPostProcessor,然后通過getBean()方法實例化,注冊到容器中;上述步驟中MergedBeanDefinitionPostProcessor類型會單獨存儲到internalPostProcessors集合中,排序后保證放到末尾;最后移除ApplicationListenerDetector重新追加到最末尾。注意:這里有個細節(jié)就是要保證高級別優(yōu)先級的BeanPostProcessor全部實例化完成后,才可以進行下一個優(yōu)先級類型的BeanPostProcessor,因為BeanPostProcessor主要就是圍繞Bean實例化進行擴展,這樣就可以保證高優(yōu)先級的BeanPostProcessor可以參與到對低優(yōu)先級的BeanPostProcessor實例化過程中。
和上步invokeBeanFactoryPostProcessors不同的是,這里只是把所有的BeanPostProcessor注冊進來,并沒有去執(zhí)行,因為這也很好理解:BeanPostProcessor是圍繞在Bean實例化周圍的擴展點,這里服務Bean存儲在容器中基本都還是BeanDefinition,還沒有進行實例化。
initMessageSource方法主要是處理國際化相關工作,后臺開發(fā)中很少涉及,這里就不展開分析。
initApplicationEventMulticaster是上下文環(huán)境中初始化一個事件廣播器,用于事件發(fā)布,后續(xù)分析Spring事件機制再整體分析。
onRefresh默認是空實現,模板模式設計主要用于子類擴展。可以參照SpringBoot中ServletWebServerApplicationContext這個類,重寫了onRefresh()方法,在這個方法中完成內嵌Servlet容器的創(chuàng)建:Tomcat、Jetty、Undertow,將程序內嵌一個Servlet容器后,就可以獨立運行。
registerListeners方法主要完成事件監(jiān)聽器注冊,將實現了ApplicationListener接口的監(jiān)聽器bean注冊到ApplicationEventMulticaster上,在注冊完以后,還會將其前期的事件發(fā)布給相匹配的監(jiān)聽器。后續(xù)分析Spring事件機制再整體分析。
熱門
聯系我們:435 226 40 @qq.com
版權所有 重播新聞網 www.zzx33.com 京ICP備2022022245號-17