2023-09-16
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/104975844

invokeBeanDefinitionRegistryPostProcessors调用处理器方法

继续我们前面的讲,后置处理器创建出来了,然后要进行处理了,遍历所有的进行处理。

    	private static void invokeBeanDefinitionRegistryPostProcessors(
    			Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
    
    		for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
    			postProcessor.postProcessBeanDefinitionRegistry(registry);
    		}
    	}

当然也包括我们刚才的扩展的,而且我们扩展的优先级最高,已经被排到前面了:

202309162311264961.png
调用了处理方法,只是打个信息。

202309162311270432.png

大致处理流程

202309162311281023.png

ConfigurationClassPostProcessor的处理

这里才是重要的,看看这个处理器怎么来解析配置类。
先检测是否已经处理过,再调用processConfigBeanDefinitions处理。

    	@Override
    	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    		int registryId = System.identityHashCode(registry);
    		if (this.registriesPostProcessed.contains(registryId)) {
    			throw new IllegalStateException(
    					"postProcessBeanDefinitionRegistry already called on this post-processor against " + registry);
    		}
    		if (this.factoriesPostProcessed.contains(registryId)) {
    			throw new IllegalStateException(
    					"postProcessBeanFactory already called on this post-processor against " + registry);
    		}
    		this.registriesPostProcessed.add(registryId);//先添加表示处理了
    
    		processConfigBeanDefinitions(registry);
    	}

processConfigBeanDefinitions

首先选出配置类的bean定义

取出所有的bean定义名字,遍历获取bean定义,然后判断是否有配置属性CONFIGURATION_CLASS_ATTRIBUTE,没有的话就检查是否是配置类,是就话就封装成BeanDefinitionHolder添加到configCandidates中。

    		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    		String[] candidateNames = registry.getBeanDefinitionNames();//获取所有bean定义名字
    
    		for (String beanName : candidateNames) {
    			BeanDefinition beanDef = registry.getBeanDefinition(beanName);
    			if (beanDef.getAttribute(ConfigurationClassUtils.CONFIGURATION_CLASS_ATTRIBUTE) != null) {//如果有这个属性表示处理过了
    				if (logger.isDebugEnabled()) {
    					logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
    				}
    			}
    			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
    				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));//把Configuration注解的bean定义到configCandidates
    			}
    		}
    
    		// Return immediately if no @Configuration classes were found
    		if (configCandidates.isEmpty()) {//没有配置候选就返回
    			return;
    		}

ConfigurationClassUtils的checkConfigurationClassCandidate

别看代码很长,其实就是先获取bean的全限定名,然后判断是否是注解类型,是的话就取出注解元数据,否则就判断是否存在BeanClass,有的话就取他的元数据,否则就用URL去加载类名对应的类,取出元数据。然后获取元数据上的Configuration注解的属性,默认proxyBeanMethods=true,后面会使用CGLIB动态代理增强,所以要设置一个full的属性,否则就设置lite属性。最后如果设置了Order注解,就设置序号属性。

    	public static boolean checkConfigurationClassCandidate(
    			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
    		//获取Bean全限定名
    		String className = beanDef.getBeanClassName();
    		if (className == null || beanDef.getFactoryMethodName() != null) {
    			return false;
    		}
    
    		AnnotationMetadata metadata;
    		//是注解类型,元数据类名跟bean类名一样
    		if (beanDef instanceof AnnotatedBeanDefinition &&
    				className.equals(((AnnotatedBeanDefinition) beanDef).getMetadata().getClassName())) {
    			// Can reuse the pre-parsed metadata from the given BeanDefinition...
    			metadata = ((AnnotatedBeanDefinition) beanDef).getMetadata();//获得注解的元数据
    		}
    		else if (beanDef instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) beanDef).hasBeanClass()) {
    			// Check already loaded Class if present...存在BeanClass就取出来
    			// since we possibly can't even load the class file for this Class.
    			Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
    			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
    					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
    					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
    					EventListenerFactory.class.isAssignableFrom(beanClass)) {
    				return false;
    			}
    			metadata = AnnotationMetadata.introspect(beanClass);//取出元数据
    		}
    		else {
    			try {
    				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(className);
    				metadata = metadataReader.getAnnotationMetadata();
    			}
    			catch (IOException ex) {
    				if (logger.isDebugEnabled()) {
    					logger.debug("Could not find class file for introspecting configuration annotations: " +
    							className, ex);
    				}
    				return false;
    			}
    		}
    		//获取Configuration注解的属性
    		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {//如果proxyBeanMethods=true,可能会用动态代理
    			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);//设置属性为full
    		}
    		else if (config != null || isConfigurationCandidate(metadata)) {//设置属性为lite
    			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
    		}
    		else {
    			return false;
    		}
    
    		// It's a full or lite configuration candidate... Let's determine the order value, if any.
    		Integer order = getOrder(metadata);
    		if (order != null) {//如果有排序,设置序号属性
    			beanDef.setAttribute(ORDER_ATTRIBUTE, order);
    		}
    
    		return true;
    	}

最后执行完就只有一个配置类:

202309162311287924.png

isConfigurationCandidate是否是配置候选类(重点)

202309162311293265.png
我们知道加了Configuration注解肯定是配置类,但是不加其实也可以是配置类,只要不是接口类型,有Component ComponentScan Import ImportResource任意一个注解,或者有bean注解的方法。只是加了Configuration注解后,里面有个默认proxyBeanMethods=true的属性,可以使用动态代理做增强的,具体用法后面会总结。我们看这个是否是配置候选类的方法:

    //是配置候选类型的集合
    	private static final Set<String> candidateIndicators = new HashSet<>(8);
    
    	static {//添加配置类型的集合Component ComponentScan Import ImportResource
    		candidateIndicators.add(Component.class.getName());
    		candidateIndicators.add(ComponentScan.class.getName());
    		candidateIndicators.add(Import.class.getName());
    		candidateIndicators.add(ImportResource.class.getName());
    	}
    
    public static boolean isConfigurationCandidate(AnnotationMetadata metadata) {
    		// Do not consider an interface or an annotation...
    		if (metadata.isInterface()) {//非接口
    			return false;
    		}
    
    		// Any of the typical annotations found?存在 Component ComponentScan Import ImportResource任意一个注解
    		for (String indicator : candidateIndicators) {
    			if (metadata.isAnnotated(indicator)) {
    				return true;
    			}
    		}
    
    		// Finally, let's look for @Bean methods...
    		try {//或者bean方法注解
    			return metadata.hasAnnotatedMethods(Bean.class.getName());
    		}
    		catch (Throwable ex) {
    			if (logger.isDebugEnabled()) {
    				logger.debug("Failed to introspect @Bean methods on class [" + metadata.getClassName() + "]: " + ex);
    			}
    			return false;
    		}
    	}

排序,设置bean名字生成器,获取环境

这里就是把上面的configCandidates进行排序,然后设置bean名字生成器,一般就是默认的,然后获取环境

    		configCandidates.sort((bd1, bd2) -> {
    			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
    			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
    			return Integer.compare(i1, i2);
    		});
    		//检测是否有自定义的bean name生成器
    		// Detect any custom bean name generation strategy supplied through the enclosing application context
    		SingletonBeanRegistry sbr = null;
    		if (registry instanceof SingletonBeanRegistry) {
    			sbr = (SingletonBeanRegistry) registry;
    			if (!this.localBeanNameGeneratorSet) {
    				BeanNameGenerator generator = (BeanNameGenerator) sbr.getSingleton(
    						AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR);
    				if (generator != null) {//如果有自定义的beanname生成器,就是何止进去
    					this.componentScanBeanNameGenerator = generator;
    					this.importBeanNameGenerator = generator;
    				}
    			}
    		}
    
    		if (this.environment == null) {
    			this.environment = new StandardEnvironment();
    		}

创建配置类解析器,开始解析

创建解析器,将配置类集合转成LinkedHashSet,并创建一个已经解析成ConfigurationClass类型的HashSet表示已经解析好的配置类。然后开始解析,解析完后会进行验证,因为里面可能会进行CGLIB的动态代理,具体后面会讲,然后将解析好的ConfigurationClass集合返回,删除上一次已经解析过的,留下的就是新解析出来的,然后对解析出来的ConfigurationClass集合进行bean定义的加载,因为前面解析的时候可能会有@import,@bean等属性,会有新的bean定义。处理完就放入已解析过的集合alreadyParsed 中,然后清空,判断加载后的bean定义的数量是否有增加,有的话说明就有新的bean定义了,又要重新去判断是否是配置类,是的话就放到candidates中,然后继续解析,一直循环知道没有配置类为止。

    // Parse each @Configuration class 创建配置解析器
    		ConfigurationClassParser parser = new ConfigurationClassParser(
    				this.metadataReaderFactory, this.problemReporter, this.environment,
    				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    		//转成LinkedHashSet
    		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());//已经解析过的
    		do {//开始解析configCandidates元素
    			parser.parse(candidates);//解析配置类集合
    			parser.validate();//验证如果要CGLIB代理的话,条件是否满足,比如类不能final,bean注解方法要可覆盖
    			//获得解析好的ConfigurationClass
    			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
    			configClasses.removeAll(alreadyParsed);//删除已经解析的
    
    			// Read the model and create bean definitions based on its content
    			if (this.reader == null) {//创建配置类bean定义读取器
    				this.reader = new ConfigurationClassBeanDefinitionReader(
    						registry, this.sourceExtractor, this.resourceLoader, this.environment,
    						this.importBeanNameGenerator, parser.getImportRegistry());
    			}
    			this.reader.loadBeanDefinitions(configClasses);//加载bean定义
    			alreadyParsed.addAll(configClasses);//添加到已处理的集合
    
    			candidates.clear();//处理完一次就清空
    			if (registry.getBeanDefinitionCount() > candidateNames.length) {//如果有加载到新的bean定义,再继续加载
    				String[] newCandidateNames = registry.getBeanDefinitionNames();//总的名字
    				Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));//处理过的名字
    				Set<String> alreadyParsedClasses = new HashSet<>();
    				for (ConfigurationClass configurationClass : alreadyParsed) {
    					alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
    				}
    				for (String candidateName : newCandidateNames) {
    					if (!oldCandidateNames.contains(candidateName)) {//处理新的
    						BeanDefinition bd = registry.getBeanDefinition(candidateName);
    						if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
    								!alreadyParsedClasses.contains(bd.getBeanClassName())) {//符合配置类要求就添加到candidates
    							candidates.add(new BeanDefinitionHolder(bd, candidateName));
    						}
    					}
    				}
    				candidateNames = newCandidateNames;//更新候选名字
    			}
    		}
    		while (!candidates.isEmpty());

其实就是一个解析配置类的过程,然后解析之后会发现可能配置类里面还会带有其他配置类的定义,然后就得循环去解析新的配置类,直到最后没有新的配置类的bean定义。

其中有几个核心的方法后面会介绍,里面涉及到如何解析配置类的注解,CGLIB的动态代理等等。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。

阅读全文