Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors

文章目录

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors


Pre

Spring5源码 - 04 invokeBeanFactoryPostProcessors 源码解读_1

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_2


细说invokeBeanDefinitionRegistryPostProcessors

前两篇博文 我们过了一下这个方法的主干流程,其中有个关键的方法,我们没有细说就是这个invokeBeanDefinitionRegistryPostProcessors。

这个方法很重要,本篇博文我们就一起来剖析下。

话不多说,还是下来梳理主干流程,然后再对着源码过一遍


流程图

我们来看流程图

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors


源码分析

我们从头跟一下

AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class);

进入到AnnotationConfigApplicationContext的构造函数中

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
		//调用构造函数
		this();
		//注册我们的配置类
		register(annotatedClasses);
		//IOC容器刷新接口
		refresh();
	}

这里我们关注refresh方法,这个方法太重要了,里面非常深的调用链,我们这里先有个大概的认知

@Override
	public 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);

这个方法主要干的三件事儿

  1. 找到开发人员传入主配置类
  2. 创建一个配置类解析器对象
  3. 解析我们的配置类 parser.parse(candidates);
  4. 把解析出来的配置类注册到容器中 this.reader.loadBeanDefinitions(configClasses);

我们重点关注第三步 和第四步

先看第三步

解析配置类 parser.parse(candidates)

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors

所以重点看

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));
	}

进入

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors

关注

sourceClass = doProcessConfigurationClass(configClass, sourceClass);

这里面就是处理各种注解【@propertySource、@ComponentScan 、@Import、@ImportResource、@Bean】的地方,我们来看下源码

@Nullable
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {

		// Recursively process any member (nested) classes first
		processMemberClasses(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)) {
			//循环解析 我们解析出来的AnnotationAttributes
			for (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 annotations
		processImports(configClass, sourceClass, getImports(sourceClass), true);

		// 处理 @ImportResource annotations
		AnnotationAttributes 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 recurse
				return 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);

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors

很清晰哈

一个个的看下吧

注册@Import的bean

	private void registerBeanDefinitionForImportedConfigurationClass(ConfigurationClass configClass) {
		//获取我们的配置类的源信息
		AnnotationMetadata metadata = configClass.getMetadata();
		//构建为我们的bean定义
		AnnotatedGenericBeanDefinition configBeanDef = new AnnotatedGenericBeanDefinition(metadata);
		//设置他的scope
		ScopeMetadata 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

Spring5源码 - 05 invokeBeanFactoryPostProcessors 源码解读_3细说invokeBeanDefinitionRegistryPostProcessors

处理@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 possible
                if (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从文件加载bean
        reader.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的注册。


上一篇:带账号、密码ssh的脚本


下一篇:解读SpringBoot和SpringMVC中配置类的@Impot等导入是如何解析的