• Spring实例化源码解析之ConfigurationClassPostProcessor(二)


    ConfigurationClassPostProcessor源码 解析

    书接上回,在第一次调用invokeBeanDefinitionRegistryPostProcessors方法的时候参数currentRegistryProcessors为ConfigurationClassPostProcessor,本章主要深入这个类的postProcessBeanDefinitionRegistry方法。

    postProcessBeanDefinitionRegistry

    首先看到的这句注释就能完整的概括这章源码的全部内容:从注册表中的配置类派生更多的bean definitions。刚看这句话可能理解不出来里面的意思,那就各位看官里面请。

    	/**
    	 * Derive further bean definitions from the configuration classes in the registry.
    	 */
    	@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);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    首先为BeanDefinitionRegistry生成了一个registryId,这个就是为了检验重复加载的问题,所以前面的都只是校验,如果只看主流程这些你都可以不看,直接关注最后一行代码,processConfigBeanDefinitions(registry)。

    在这里插入图片描述

    上面这张图可以知道registry中的具体属性内容,需要我们关注的是BeanDefinitionNames和beanPostProcessors这两个。aopConfig是我启动的时候的配置类,也就是我手动注册的类(register(componentClasses)),其他的都是spring自带的,本章的ConfigurationClassPostProcessor就是。

    processConfigBeanDefinitions

    开始进入正题,接下来就慢慢的拆解processConfigBeanDefinitions方法。

    		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    		// 当前BeanFacoty中存在的BeanDefinitonNames
    		String[] candidateNames = registry.getBeanDefinitionNames();
    
    		for (String beanName : candidateNames) {
    			// 根据名称获取BeanDefinition
    			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);
    				}
    			}
    			// 检测配置候选人的条件,此处为true才会加入配置候选人
    			// private static final Set candidateIndicators = new HashSet<>(8);
    			//
    			//	static {
    			//		candidateIndicators.add(Component.class.getName());
    			//		candidateIndicators.add(ComponentScan.class.getName());
    			//		candidateIndicators.add(Import.class.getName());
    			//		candidateIndicators.add(ImportResource.class.getName());
    			//	}
    			// 也就是说只要包含这些也都是配置候选人
    			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
    				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    			}
    		}
    
    		// Return immediately if no @Configuration classes were found
    		if (configCandidates.isEmpty()) {
    			return;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    首先定义了一个configCandidates的集合,我们把他叫做后续按配置类集合,存放的是BeanDefinitionHolder,BeanDefinitionHolder和BeanDefinition是Spring框架中两个相关的概念,它们之间存在一种包含关系。

    BeanDefinition是一个接口,用于描述一个bean的定义信息,包括bean的类名、作用域、依赖关系、属性值等信息。它是Spring框架中定义bean的元数据的核心表示形式。

    BeanDefinitionHolder是一个包装类,用于持有BeanDefinition对象以及与之关联的bean名称。它包含两个主要成员变量:bean名称和BeanDefinition对象。

    在Spring框架的内部,BeanDefinitionHolder常用于在注册表中存储和管理bean的定义。它提供了一个包装机制,使得可以将bean名称与其对应的BeanDefinition关联起来,并一起存储在注册表中。

    通过BeanDefinitionHolder,可以轻松地访问和操作与特定bean相关联的BeanDefinition。它提供了一种方便的方式来获取bean的名称、获取和设置BeanDefinition的属性值等操作。

    candidateNames是一个string数组,从上面的截图可以看出,当前会有5个BeanDefinitionNames,然后进入for循环,for循环要做的事情就是把这些BeanDefinition拿出来判断是否是候选配置类。

    else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
    				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    			}
    
    • 1
    • 2
    • 3

    ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)方法就是用来判断是否是候选类,可以看出configCandidates.add方法就只在这里用到了。

    public static boolean checkConfigurationClassCandidate(
    			BeanDefinition beanDef, MetadataReaderFactory metadataReaderFactory) {
    
    		String className = beanDef.getBeanClassName();
    		if (className == null || beanDef.getFactoryMethodName() != null) {
    			return false;
    		}
    
    		AnnotationMetadata metadata;
    		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...
    			// 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;
    			}
    		}
    
    		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    		}
    		else if (config != null || isConfigurationCandidate(metadata)) {
    			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;
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    虽然上述的代码看起来很长,而且杂七杂八的逻辑判断让我们不知道如何下手,这个时候可以打端点调试一下。

    在这里插入图片描述

    唉哟,beanDef是RootBeanDefinition类型,所以会进入else if的逻辑里面,也就到了我们这段代码的第一个核心逻辑。因为这里有个return,所以在看的时候需要关注一下。

    Class<?> beanClass = ((AbstractBeanDefinition) beanDef).getBeanClass();
    			if (BeanFactoryPostProcessor.class.isAssignableFrom(beanClass) ||
    					BeanPostProcessor.class.isAssignableFrom(beanClass) ||
    					AopInfrastructureBean.class.isAssignableFrom(beanClass) ||
    					EventListenerFactory.class.isAssignableFrom(beanClass)) {
    				return false;
    			}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这段代码用于过滤掉特定类型的bean,不对它们应用后续的处理。

    具体来说,改代码中的条件判断用于检查给定的beanClass是否属于以下四个类型之一:

    1、BeanFactoryPostProcessor:实现了BeanFactoryPostProcessor接口的类,用于在容器实例化任何其他bean之前对bean工厂进行自定义修改。

    2、BeanPostProcessor:实现了BeanPostProcessor接口的类,用于在容器实例化bean时对bean进行自定义处理,例如初始化前后的操作。

    3、AopInfrastructureBean:实现了AopInfrastructureBean接口的类,用于定义AOP基础设施bean,如AOP代理工厂等。

    4、EventListenerFactory:实现了EventListenerFactory接口的类,用于创建事件监听的工厂。

    如果给定的beanClass是上述四个类型之一,那么该代码会返回false,表示不对该类型的bean应用后续的处理。

    打端点之后其实可以知道Spring自己注入的那些都会被跳过,唯独就是我们手动registry(AopConfig.class)

    在这里插入图片描述

    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;
    			}
    		}
    
    		Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
    		if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
    			beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
    		}
    		else if (config != null || isConfigurationCandidate(metadata)) {
    			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);
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    然后我们可以知道metadataReader就是元数据的读取,然后看是否含有@Configuration注解,我们的AopConfig其实是没有@Configutation注解的。

    // 容器启动
    AnnotationConfigApplicationContext annotationConfigApplicationContext =
           new AnnotationConfigApplicationContext(AopConfig.class);
    
    // AopCofig类,类似于SpringBoot的Application启动类
    @ComponentScan(value = {"com.qhyu.cloud.**"})
    public class AopConfig {
    	// 啥也没有
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    所以第二个核心逻辑就是isConfigurationCandidate(matedata),ConfigurationClassUtils类中。

    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?
    		for (String indicator : candidateIndicators) {
    			if (metadata.isAnnotated(indicator)) {
    				return true;
    			}
    		}
    
    		// Finally, let's look for @Bean methods...
    		return hasBeanMethods(metadata);
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    如果是个接口直接返回false,说明得是类才可以。candidateIndicators是一个静态的全局变量,内容是static静态代码块里加载的。

    private static final Set<String> candidateIndicators = new HashSet<>(8);
    
    	static {
    		candidateIndicators.add(Component.class.getName());
    		candidateIndicators.add(ComponentScan.class.getName());
    		candidateIndicators.add(Import.class.getName());
    		candidateIndicators.add(ImportResource.class.getName());
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    很明朗了对吧。就是包含这些注解的,都会被加入到configCandidates配置后端名单中。

    跳出方法查看beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);这行代码将一个名为 CONFIGURATION_CLASS_ATTRIBUTE 的属性设置为值 CONFIGURATION_CLASS_LITE。

    在Spring中,CONFIGURATION_CLASS_ATTRIBUTE是一个常量,用于指示配置类的类型。它通常用于标识配置类是以何种方式加载和处理的。

    CONFIGURATION_CLASS_LITE 和 CONFIGURATION_CLASS_FULL 是两种可能的取值,表示不同类型的配置类:

    1、CONFIGURATION_CLASS_LITE:表示轻量级配置类。这种类型的配置类通常是通过@Configuration注解进行标记的,但不包含任何特殊的逻辑处理。它们可能指示简单地定义一些bean的声明,而没有涉及复杂的依赖注入、条件化配置或其他高级功能。轻量级配置类在处理过程中会更加简单和高效。

    2、CONFIGURATION_CLASS_FULL:表示完全配置类。这种类型的配置类包含了更多的复杂逻辑和功能,如条件配置、依赖注入、AOP、事件处理等。完全配置类可能使用了更多的Spring功能和特性,需要进行更全面的解析和处理。

    重回processConfigBeanDefinitions

    去过了最远的地方,还得回到最原来的地方。

    public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    		//registry 也就是BeanFactory(ConfigurableListableBeanFactory)
    		// configCandidates Candidates候选人
    		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
    		// 当前BeanFacoty中存在的BeanDefinitonNames
    		String[] candidateNames = registry.getBeanDefinitionNames();
    
    		for (String beanName : candidateNames) {
    			// 根据名称获取BeanDefinition
    			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);
    				}
    			}
    			// 检测配置候选人的条件,此处为true才会加入配置候选人
    			// private static final Set candidateIndicators = new HashSet<>(8);
    			//
    			//	static {
    			//		candidateIndicators.add(Component.class.getName());
    			//		candidateIndicators.add(ComponentScan.class.getName());
    			//		candidateIndicators.add(Import.class.getName());
    			//		candidateIndicators.add(ImportResource.class.getName());
    			//	}
    			// 也就是说只要包含这些也都是配置候选人
    			else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
    				configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
    			}
    		}
    
    		// Return immediately if no @Configuration classes were found
    		if (configCandidates.isEmpty()) {
    			return;
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    当ConfigurationClassUtils类的isConfigurationCandidate返回true之后就说明ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)返回true。所以会把当前beanDefinitionHolder加入到配置候选集合中。当然如果配置候选集合为空就直接return了。

    接下来这个就是单纯的排序,这边直接跳过,不耽误时间,有兴趣自己深入,或者后续单独讲一期排序。

    // Sort by previously determined @Order value, if applicable
    		configCandidates.sort((bd1, bd2) -> {
    			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
    			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
    			return Integer.compare(i1, i2);
    		});
    
    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) {
    					this.componentScanBeanNameGenerator = generator;
    					this.importBeanNameGenerator = generator;
    				}
    			}
    		}
    
    		if (this.environment == null) {
    			this.environment = new StandardEnvironment();
    		}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    排序下面这段代码用于获取并设置组件扫描时使用的Bean名称生成器。

    首先定义了一个SingletonBeanRegistry类型的变量sbr并初始化为null。然后,通过检查registry对象是否是SingletonBeanRegistry的实例来确定是否可以进行后续的操作。

    如果registry是SingletonBeanRegistry的实例,说明它是一个单例Bean注册表,可以用于获取和设置单例Bean。接下来,讲registry对象强制转换为SingletonBeanRegistry类型,并将其赋值给sbr变量。

    代码尝试从sbr中获取名为AnnotationConfigUtils.CONFIGURATION_BEAN_NAME_GENERATOR的单例Bean。这个常量是用于指定配置类的Bean名称生成器的键。如果能够获取到该单例Bean,说明已经为配置类设置了特定的Bean名称生成器。如果generator不为null,代码将获取到的generator赋值给两个成员变量:componentScanBeanNameGenerator和importBeanNameGenerator。这两个成员变量分别用于组件扫描和导入Bean时使用的Bean名称生成器。

    通过这段代码,可以实现以下功能:

    • 检查是否有合适的单例Bean注册表可用。
    • 获取配置类的Bean名称生成器。
    • 设置组件扫描和导入Bean时使用的Bean名称生成器。

    这样做的目的是为了在Spring的组件扫描和Bean加载过程中使用适当的Bean名称生成器,以确保生成的Bean名称符合预期并与其他组件协调一致。

    // Parse each @Configuration class
    		ConfigurationClassParser parser = new ConfigurationClassParser(
    				this.metadataReaderFactory, this.problemReporter, this.environment,
    				this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    
    		// 这是候选人Set,去重
    		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
    		// 以及解析了的配置类
    		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
    		do {
    			StartupStep processConfig = this.applicationStartup.start("spring.context.config-classes.parse");
    			// 解析我们的配置类,我们使用AnnotationConfigApplicationContent启动的时候,使用的构造函数进行创建
    			// 也就是加入了@ComponentScan注解,需要根据里面的路径扫描包路径,从而找到所有需要被Spring管理的Bean的beanDefiniton信息
    			// ConfigurationClassParser去解析我们的AopConfig类.这个类只会在启动的时候呗调用一次
    			parser.parse(candidates);
    			// 验证
    			parser.validate();
    
    			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) {
    				this.reader = new ConfigurationClassBeanDefinitionReader(
    						registry, this.sourceExtractor, this.resourceLoader, this.environment,
    						this.importBeanNameGenerator, parser.getImportRegistry());
    			}
    			// ImportBeanDefinitionRegistrar扫描实现了这个接口的方法
    			// ConfigurationClassParser解析的在这里又读出来,这里需要打断点再观察一下。
    			this.reader.loadBeanDefinitions(configClasses);
    			alreadyParsed.addAll(configClasses);
    			processConfig.tag("classCount", () -> String.valueOf(configClasses.size())).end();
    
    			candidates.clear();
    			if (registry.getBeanDefinitionCount() > candidateNames.length) {
    				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.add(new BeanDefinitionHolder(bd, candidateName));
    						}
    					}
    				}
    				candidateNames = newCandidateNames;
    			}
    		}
    		while (!candidates.isEmpty());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54

    这段代码是最最最核心的内容,还会引入一个新的类来解析和处理候选配置类,本章我们主要梳理这段代码的逻辑,深入的源码将在下一章节来分析。

    1、创建一个ConfigurationClassParser对象并进行初始化。该对象用于解析候选配置类,并生成相应的配置类对象(ConfigurationClass)和相关的Bean定义。

    2、创建一个Set类型的变量candidates,用于存储候选的Bean定义持有者。这些候选人是从configCandidates中获取的,它是一个包含待解析的候选配置类的集合。

    3、创建一个Set类型的变量alreadyParsed,用于存储已经解析过的配置类。

    4、进入循环,直到候选人集合为空。在每次循环迭代中,执行以下操作:
    a. 启动一个性能追踪步骤,记录解析过程的性能指标。
    b. 调用parser.parse(candidates)方法,解析candidates中的候选配置类。在解析过程中,将根据配置类的内容创建相应的Bean定义。
    c. 调用parser.validate()方法,对解析后的配置类进行验证,确保它们符合规范。
    d. 获取解析后的配置类集合,并将其与已解析的配置类集合进行比较,筛选出新增的配置类。
    e. 如果this.reader为null,则创建一个ConfigurationClassBeanDefinitionReader对象,用于读取模型并基于其内容创建Bean定义。
    f. 调用this.reader.loadBeanDefinitions(configClasses)方法,将配置类转换为Bean定义,并注册到Bean定义注册表中。
    g. 将已解析的配置类添加到alreadyParsed集合中。
    h. 根据新的Bean定义数量更新candidateNames数组,并筛选出新增的候选人Bean定义。
    i. 清空candidates集合,准备下一次循环迭代。

    整个过程会迭代解析和处理所有的候选配置类,将它们转换为相应的Bean定义,并注册到Bean定义注册表中。这样,这些候选配置类中声明的Bean就可以在应用程序中使用和管理了。

    总结

    本章就ConfigurationClassPostProcessor的processConfigBeanDefinitions方法做了深入的源码分析,描述了方法内部所完成的spring实例化的过程,具体的在项目启动过程中如何将我们自己定义的需要被spring管理的bean的定义信息放入工厂中,会在下一个章节进行详细的分析。

  • 相关阅读:
    最通俗易懂的LSTM讲解,一个例子理解通透!!
    我的十年编程路 2022年篇
    vue中ref的用法
    springboot增加过滤器后中文乱码
    io集合管理
    智慧用电安全云监控系统
    中文编程工具开发语言编程案例:会员VIP管理系统软件实例
    .NET性能优化-是时候换个序列化协议了
    激光slam学习
    生信教程:多序列比对
  • 原文地址:https://blog.csdn.net/Tanganling/article/details/133034473