欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-03-19 13:25:04
...

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的注册。