javascript
Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors
文章目錄
- Pre
- 細說invokeBeanDefinitionRegistryPostProcessors
- 流程圖
- 源碼分析
- 解析配置類 parser.parse(candidates)
- 配置類注冊到容器中 this.reader.loadBeanDefinitions(configClasses)
- 注冊@Import的bean
- 注冊@Bean的bean
- 注冊@ImportResources的bean
- 注冊ImportBeanDefinition的bean
Pre
Spring5源碼 - 04 invokeBeanFactoryPostProcessors 源碼解讀_1
Spring5源碼 - 05 invokeBeanFactoryPostProcessors 源碼解讀_2
細說invokeBeanDefinitionRegistryPostProcessors
前兩篇博文 我們過了一下這個方法的主干流程,其中有個關鍵的方法,我們沒有細說就是這個invokeBeanDefinitionRegistryPostProcessors。
這個方法很重要,本篇博文我們就一起來剖析下。
話不多說,還是下來梳理主干流程,然后再對著源碼過一遍
流程圖
我們來看流程圖
源碼分析
我們從頭跟一下
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);進入到AnnotationConfigApplicationContext的構造函數中
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {//調用構造函數this();//注冊我們的配置類register(annotatedClasses);//IOC容器刷新接口refresh();}這里我們關注refresh方法,這個方法太重要了,里面非常深的調用鏈,我們這里先有個大概的認知
@Overridepublic void refresh() throws BeansException, IllegalStateException { //1:準備刷新上下文環境prepareRefresh();//2:獲取告訴子類初始化Bean工廠ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();//3:對bean工廠進行填充屬性prepareBeanFactory(beanFactory);try {// 第四:留個子類去實現該接口postProcessBeanFactory(beanFactory);// 調用我們的bean工廠的后置處理器.invokeBeanFactoryPostProcessors(beanFactory);// 調用我們bean的后置處理器registerBeanPostProcessors(beanFactory);// 初始化國際化資源處理器.initMessageSource();// 創建事件多播器initApplicationEventMulticaster();// 這個方法同樣也是留個子類實現的springboot也是從這個方法進行啟動tomat的.onRefresh();//把我們的事件監聽器注冊到多播器上registerListeners();//實例化我們剩余的單實例bean.finishBeanFactoryInitialization(beanFactory);// 最后容器刷新 發布刷新事件(Spring cloud也是從這里啟動的)finishRefresh();}}我們先重點關注【invokeBeanFactoryPostProcessors(beanFactory);】
跟進去,重點看 invokeBeanFactoryPostProcessors
//傳入bean工廠和獲取applicationContext中的bean工廠后置處理器(但是由于沒有任何實例化過程,所以傳遞進來的為空)PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());繼續,重點關注
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);這個方法就是我們今天要研究的源碼
/*** Invoke the given BeanDefinitionRegistryPostProcessor beans.*/private static void invokeBeanDefinitionRegistryPostProcessors(Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {//獲取容器中的ConfigurationClassPostProcessor的后置處理器進行bean定義的掃描for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {postProcessor.postProcessBeanDefinitionRegistry(registry);}}
這里就一個,那就是 ConfigurationClassPostProcessor
僅需跟進去 ,看ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry方法
//真正的解析我們的bean定義processConfigBeanDefinitions(registry);這個方法主要干的三件事兒
我們重點關注第三步 和第四步
先看第三步
解析配置類 parser.parse(candidates)
所以重點看
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());跟進去
/*** 真的解析我們的配置類* @param metadata 配置類的源信息* @param beanName 當前配置類的beanName* @throws IOException*/protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {/*** 第一步:把我們的配置類源信息和beanName包裝成一個ConfigurationClass 對象*/processConfigurationClass(new ConfigurationClass(metadata, beanName));}進入
關注
sourceClass = doProcessConfigurationClass(configClass, sourceClass);這里面就是處理各種注解【@propertySource、@ComponentScan 、@Import、@ImportResource、@Bean】的地方,我們來看下源碼
@Nullableprotected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)throws IOException {// Recursively process any member (nested) classes firstprocessMemberClasses(configClass, sourceClass);//處理我們的@propertySource注解的for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), PropertySources.class,org.springframework.context.annotation.PropertySource.class)) {if (this.environment instanceof ConfigurableEnvironment) {processPropertySource(propertySource);}else {logger.warn("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +"]. Reason: Environment must implement ConfigurableEnvironment");}}//解析我們的 @ComponentScan 注解//從我們的配置類上解析處ComponentScans的對象集合屬性Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);if (!componentScans.isEmpty() &&!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {//循環解析 我們解析出來的AnnotationAttributesfor (AnnotationAttributes componentScan : componentScans) {//把我們掃描出來的類變為bean定義的集合 真正的解析Set<BeanDefinitionHolder> scannedBeanDefinitions =this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());//循環處理我們包掃描出來的bean定義for (BeanDefinitionHolder holder : scannedBeanDefinitions) {BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();if (bdCand == null) {bdCand = holder.getBeanDefinition();}//判斷當前掃描出來的bean定義是不是一個配置類,若是的話 直接進行遞歸解析if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {//遞歸解析parse(bdCand.getBeanClassName(), holder.getBeanName());}}}}// 處理 @Import annotationsprocessImports(configClass, sourceClass, getImports(sourceClass), true);// 處理 @ImportResource annotationsAnnotationAttributes importResource =AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);if (importResource != null) {String[] resources = importResource.getStringArray("locations");Class<? extends BeanDefinitionReader> readerClass = importResource.getClass("reader");for (String resource : resources) {String resolvedResource = this.environment.resolveRequiredPlaceholders(resource);configClass.addImportedResource(resolvedResource, readerClass);}}// 處理 @Bean methods 獲取到我們配置類中所有標注了@Bean的方法Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);for (MethodMetadata methodMetadata : beanMethods) {configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));}// 處理配置類接口的processInterfaces(configClass, sourceClass);// 處理配置類的父類的if (sourceClass.getMetadata().hasSuperClass()) {String superclass = sourceClass.getMetadata().getSuperClassName();if (superclass != null && !superclass.startsWith("java") &&!this.knownSuperclasses.containsKey(superclass)) {this.knownSuperclasses.put(superclass, configClass);// Superclass found, return its annotation metadata and recursereturn sourceClass.getSuperClass();}}// 沒有父類解析完成return null;}配置類注冊到容器中 this.reader.loadBeanDefinitions(configClasses)
第三步完成了,我們來看下這一步Spring是如和把配置類注冊到容器中的
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();//注冊我們的配置類到容器中for (ConfigurationClass configClass : configurationModel) {loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);}}那自然就是
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);很清晰哈
一個個的看下吧
注冊@Import的bean
private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {//獲取我們的配置類的源信息AnnotationMetadata metadata = configClass.getMetadata();//構建為我們的bean定義AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);//設置他的scopeScopeMetadata scopeMetadata = scopeMetadataResolver.resolveScopeMetadata(configBeanDef);configBeanDef.setScope(scopeMetadata.getScopeName());//獲取bean的名稱String configBeanName = this.importBeanNameGenerator.generateBeanName(configBeanDef, this.registry);//處理我們的JRS250組件的AnnotationConfigUtils.processCommonDefinitionAnnotations(configBeanDef, metadata);BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(configBeanDef, configBeanName);definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);//注冊我們的bean定義到我們的容器中this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());configClass.setBeanName(configBeanName);if (logger.isDebugEnabled()) {logger.debug("Registered bean definition for imported class '" + configBeanName + "'");}}重點就是
this.registry.registerBeanDefinition(definitionHolder.getBeanName(), definitionHolder.getBeanDefinition());注冊@Bean的bean
處理@Bean可以跟的各種屬性
注冊@ImportResources的bean
private void loadBeanDefinitionsFromImportedResources(Map<String, Class<? extends BeanDefinitionReader>> importedResources) {// reader實例緩存Map<Class<?>, BeanDefinitionReader> readerInstanceCache = new HashMap<>();// 循環處理<配置文件路徑-reader>importedResources.forEach((resource, readerClass) -> {// 如果注解配置的Reader是默認的(我們一般其實也不改)if (BeanDefinitionReader.class == readerClass) {if (StringUtils.endsWithIgnoreCase(resource, ".groovy")) {// 如果文件名是.groovy結尾,則使用GroovyBeanDefinitionReader// 說實話我也第一次知道還可以用groovy腳本來做spring的配置文件// 后面我去看了一下BeanDefinitionReader這個接口的實現類,發現還一個// PropertiesBeanDefinitionReader,感興趣的同學可以去研究一下readerClass = GroovyBeanDefinitionReader.class;}else {// 默認情況下我們使用XmlBeanDefinitionReader readerClass = XmlBeanDefinitionReader.class;}}// 先從緩存拿BeanDefinitionReader reader = readerInstanceCache.get(readerClass);if (reader == null) {try {// 拿不到就新建一個,配置的reader類必須有一個只有BeanDefinitionRegistry參數的構造器reader = readerClass.getConstructor(BeanDefinitionRegistry.class).newInstance(this.registry);// Delegate the current ResourceLoader to it if possibleif (reader instanceof AbstractBeanDefinitionReader) {AbstractBeanDefinitionReader abdr = ((AbstractBeanDefinitionReader) reader);abdr.setResourceLoader(this.resourceLoader);abdr.setEnvironment(this.environment);}readerInstanceCache.put(readerClass, reader);}catch (Throwable ex) {throw new IllegalStateException("Could not instantiate BeanDefinitionReader class [" + readerClass.getName() + "]");}}// 使用reader從文件加載beanreader.loadBeanDefinitions(resource);}); }默認情況下 是創建一個XmlBeanDefinitionReader來解析加載我們的配置文件中定義的bean的。
注冊ImportBeanDefinition的bean
private void loadBeanDefinitionsFromRegistrars(Map<ImportBeanDefinitionRegistrar, AnnotationMetadata> registrars) {registrars.forEach((registrar, metadata) ->registrar.registerBeanDefinitions(metadata, this.registry));}很直觀了哈 ,循環直接調用ImportBeanDefinitionRegistrar.registerBeanDefinitions方法進行beanDefinition的注冊。
總結
以上是生活随笔為你收集整理的Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring5 - Bean的初始化和销
- 下一篇: Spring5源码 - 00 IOC容器