?這次關注的是類加載實例化部分代碼。
? ? spring中加載類在代碼?ConfigurationClassPostProcessor 中實現的。
? ? 1:ConfigurationClassPostProcessor 是在AnnotationConfigEmbeddedWebApplicationContext 創建時,調用接口AnnotationConfigUtils#registerAnnotationConfigProcessors添加的bean定義,代碼如下:
2:在?AbstractApplicationContext 的核心方法?refresh() 里,會調用 invokeBeanFactoryPostProcessors(beanFactory) 方法,此方法里會調用?ConfigurationClassPostProcessor 的?postProcessBeanDefinitionRegistry 方法,就是在此方法里加載了相關類。
? ? 3:postProcessBeanDefinitionRegistry 的方法里,會調用方法?processConfigBeanDefinitions,該方法的邏輯如下:
? ? 3.1:獲取所有的bean定義名稱,此時入口有main方法的類肯定是可以獲取到。
? ? 3.2:對每一個bean名稱,獲取對應的bean定義信息,判斷其是否有注解@Configuration而且加載過,如果有@Configuration而且沒有加載過,加入列表configCandidates,并設置已經加載的屬性(在 bean定義的attributes屬性里,有org.springframework.context.annotation.ConfigurationClassPostProcessor.configurationClass 的key值)。代碼如下:
? ? ? ? 3.3:如果有多個類有@Configuration注解,則進行排序。一般情況下,這里只有入庫啟動類一個。
? ? ? ? 3.4:調用ConfigurationClassParser#parse(Set<BeanDefinitionHolder>) 解析有@Configuration的類。
? ? ? ? 3.5:獲取解析得到的ConfigurationClass,針對每一個ConfigurationClass,調用?ConfigurationClassBeanDefinitionReader#loadBeanDefinitions 方法處理其里面的@Import,@ImportResoure 引入加載的內容。
? ? 4:ConfigurationClassParser#parse 里的函數調用關系如下:
? ? parse -->?processConfigurationClass -->??doProcessConfigurationClass。
? ??doProcessConfigurationClass 函數的邏輯如下:
? ? ????4.1:查找ConfigurationClass的內部類,如果內部類也有注解@Configuration。那么遞歸調用方法:processConfigurationClass。
? ? ? ? 4.2:判斷類是否有注解:@ComponentScans。如此有這個注解,調用函數ComponentScanAnnotationParser#parse 處理。其處理邏輯如下:
? ? ? ? ? ? 4.2.1:解析注解@ComponentScans的屬性,比如:nameGenerator,scopedProxy,includeFilters,lazyInit,basePackages等。
? ? ? ? ? ? 4.2.2:如果沒有指定屬性basePackages 和?basePackageClasses,則掃描路徑默認為當前ConfigurationClass所在的包路徑。
? ? ? ? ? ? 4.2.3:使用?PathMatchingResourcePatternResolver#getResources 掃描指定包路徑下的所有class文件,并加載。
? ? ? ? ? ? 4.2.4:判斷加載的類是有有注解@Component,如果有,生成bean定義對象:ScannedGenericBeanDefinition。
? ? ? ? ? ? 4.2.5:解析類上的@Scope,@Lazy, @Primary, @DependsOn等屬性。
? ? ? ? ? ? 4.2.6:對掃描出來的bean定義,添加到beanFatory的緩存中。
? ? ? ? ? ? 4.3:對上一步掃描出來的bean定義,如果其有注解@Configuration,則遞歸調用方法:processConfigurationClass。
? ? ? ? ? ? 4.4:判斷ConfigurationClass是否有@Import注解。
? ? ? ? ? ? 4.5:如果Import類實現了ImportSelector接口,則加入緩存:deferredImportSelectors。 如果Import類實現了ImportBeanDefinitionRegistrar接口,則加入:importBeanDefinitionRegistrars緩存。如果都不是,則遞歸調用方法:processConfigurationClass。代碼:processImports(configClass, sourceClass, getImports(sourceClass), true);
? ??????????
? ? ? ? ? ? 4.6:判斷ConfigurationClass是否有@ImportResource注解。如果有,則把locations屬性指定的xml文件資源添加到緩存:importedResources。
? ? ? ? ? ? 4.7:判斷ConfigurationClass的方法是否有@Bean注解。如果有,加入beanMethods緩存。
? ? ? ? ? ? 4.8:對于beanMethods緩存中的每個方法,生成ConfigurationClassBeanDefinition bean定義對象。并解析initMethod等屬性,并注冊到緩存。實現方法:ConfigurationClassBeanDefinitionReader#loadBeanDefinitionsForBeanMethod。
? ? ? ? ? ? 4.9:對于@ImportResoure引入的資源:importedResources。使用XmlBeanDefinitionReader.loadBeanDefinitions 方法進行解析。
?????????????4.10:處理importBeanDefinitionRegistrars緩存中的實例,調用接口ImportBeanDefinitionRegistrar的registerBeanDefinitions方法。
? ? ? ? ? ? ? ? 4.11:對于緩存deferredImportSelectors中的對象,調用其?selectImports 接口。比如:AutoConfigurationImportSelector。該類的selectImports方法里讀取了META-INF/spring.factories里配置的?EnableAutoConfiguration。然后針對每個AutoConfiguration,按照ConfigurationClass進行解析處理(對于每一個AutoConfiguration, 會按照META-INF/spring-autoconfigure-metadata.properties的配置過濾一些不啟動的)。比如: