Spring源码对注解处理 @Bean、@ComponentScan、@Import、@ImportResource等

文章详细阐述了Spring框架中AnnotationConfigUtils在注册BeanDefinition和处理@Configuration注解时的角色。它负责注册像ConfigurationClassPostProcessor这样的后置处理器,并在XML配置(如component-scan和annotation-config)以及注解启动时调用。核心过程涉及postProcessBeanDefinitionRegistry方法,该方法触发ConfigurationClassPostProcessor解析配置类,处理@PropertySource、@ComponentScan、@Import等注解,将配置类及依赖注入到Spring容器。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

准备

AnnotationConfigUtils类

public static final String CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME =
"org.springframework.context.annotation.internalConfigurationAnnotationProcessor";

	public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
.........................省略若干代码........................
		// 注册内部管理的用于处理@configuration注解的后置处理器的bean
		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			// 注册BeanDefinition到注册表中  。ConfigurationClassPostProcessor到注册表中(以后可以实例化了)
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
.........................省略若干代码...........................
		return beanDefs;
	}
==========================注解工具注册====================
    
 调用registerAnnotationConfigProcessors(..)注册bd
// 根据条件,选择注册bean的定义信息
1. ConfigurationClassPostProcessor(bfpp) 
2. AutowiredAnnotationBeanPostProcessor(bpp)
3. CommonAnnotationBeanPostProcessor(bpp)
4. EventListenerMethodProcessor(bfpp)   
5. DefaultEventListenerFactory 等
    
在下面三个地方调用了:    
1. 
//registerBeanDefinitionParser("annotation-config", new //AnnotationConfigBeanDefinitionParser());
    
AnnotationConfigBeanDefinitionParser.java#parse{
    //注册注解配置处理器 bean信息
Set<BeanDefinitionHolder> processorDefinitions =
	//注册bfpp和bpp
  AnnotationConfigUtils.registerAnnotationConfigProcessors(parserContext.getRegistry(), source);   
}
//根据标签解析。注册解析器
registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());



2.
//处理 <component:scan base-package.. 等xml 配置
// registerBeanDefinitionParser("component-scan", new //ComponentScanBeanDefinitionParser());
    
ComponentScanBeanDefinitionParser.java#parse{
    
    ClassPathBeanDefinitionScanner#doScan(); 
    // 把扫描到的bd放进容器 
    // 注册系统bd信息
    AnnotationConfigUtils.registerAnnotationConfigProcessors(..)
  
  } 


3.本类 registerAnnotationConfigProcessors(BeanDefinitionRegistry registry) {
		registerAnnotationConfigProcessors(registry, null);
}
3.1 使用注解启动的时候,使用的。AnnotationConfigApplicationContext启动的
    //在构造方法中调用了
   	public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
      // 。。。
		this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
		AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

===========================
**总结**:上面的第一和第二,是处理xml配置(component-scan和annotation-config)的时候,注册bfpp等定义信息的。第三种是注解启动时候注册各种bd信息的。

AnnotationConfigBeanDefinitionParserComponentScanBeanDefinitionParser 的parse()中;AnnotatedBeanDefinitionReader构造方法中 等地方有调用

分析

在这里插入图片描述

  1. refresh()->
  2. invokeBeanFactoryPostProcessors(beanFactory)->
  3. 找到所有符合规则的名字。String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
  4. // 遍历处理所有符合规则的postProcessorNames,并生成对象,放进list中。(重点核心org.springframework.context.annotation.internalConfigurationAnnotationProcessor生成ConfigurationClassPostProcessor对象,这个beanName在上文准备阶段),currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
  5. 执行bfpp。 invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
  6. 调用ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry()

===》 postProcessor.postProcessBeanDefinitionRegistry(registry);

=====》ConfigurationClassPostProcessor.java#processConfigBeanDefinitions(){
//创建对象,调用解析方法
ConfigurationClassParser parser = new …
parser.parse(candidates);
}

=======>ConfigurationClassParser.java#parse(…){
//根据不同的类型,调用重载的parse方法
}
以注解为例子
->parse()
–>processConfigurationClass()
—>doProcessConfigurationClass(){
//1. 递归处理内部类,符合条件的加入到候选。遍历处理
2. 处理@PropertySource 注解
3. 处理处理@ComponentScan或者@ComponentScans注解,通过ComponentScanAnnotationParser#parse(…),进而调用ClassPathBeanDefinitionScanner#doScan(…),解析的是@Component及其子类,解析到了所有的scannedBeanDefinitions,判断是,是不是配置类,是配置类,再递归处理
4. 处理@Import注解
5. 处理@ImportResource注解
6. 处理@Bean注解的方法
7. 处理接口,jdk8支持接口@Bean注解
}

处理注解的核心方法

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// Recursively process any member (nested) classes first
			//类里面有内部类,内部类又有注解,都要解析出来,所以要递归处理。
			processMemberClasses(configClass, sourceClass, filter);
		}

		// Process any @PropertySource annotations
		// 如果配置类上加了@PropertySource注解,那么就解析加载properties文件,并将属性添加到spring上下文中。@Value(${})
		// 加到beanFactory中。实例化的时候才会赋值
		for (AnnotationAttributes propertySource : AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), PropertySources.class,
				org.springframework.context.annotation.PropertySource.class)) {
			if (this.environment instanceof ConfigurableEnvironment) {
				processPropertySource(propertySource);
			}
			else {
				logger.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// Process any @ComponentScan annotations
		// 处理@ComponentScan或者@ComponentScans注解,并将扫描包下的所有bean转换成填充后的ConfigurationClass
		// 此处就是将自定义的bean加载到IOC容器,因为扫描到的类可能也添加了@ComponentScan和@ComponentScans注解,因此需要进行递归解析
		Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
				sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);
		if (!componentScans.isEmpty() &&
				!this.conditionEvaluator.shouldSkip(sourceClass.getMetadata(), ConfigurationPhase.REGISTER_BEAN)) {
			for (AnnotationAttributes componentScan : componentScans) {
				//再创建部件扫描解析器
				//*********ClassPathBeanDefinitionScanner 类******
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config 
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					// 判断是否是一个配置类,并设置full或lite属性
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						// 通过递归方法进行解析
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// Process any @Import annotations
		// 处理 @Import注解。查找所有的@import注解,找到注解中的类并实例化。直接处理或者加入handler中
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		// Process any @ImportResource annotations
		// 处理@ImportResource注解,导入spring的配置文件.
		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);
			}
		}

		// Process individual @Bean methods
		// 处理加了@Bean注解的方法,将@Bean方法转化为BeanMethod对象,保存再集合中
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// Process default methods on interfaces
		// 处理接口的默认方法实现,从jdk8开始,接口中的方法可以有自己的默认实现,因此如果这个接口的方法加了@Bean注解,也需要被解析
		processInterfaces(configClass, sourceClass);

		// Process superclass, if any
		// 解析父类,如果被解析的配置类继承了某个类,那么配置类的父类也会被进行解析
		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();
			}
		}

		// No superclass -> processing is complete
		return null;
	}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值