3.spring源码-@Configuration

当我们给一个类加上@Configuration,spring底层到底做了哪些事情?

文章标题3:主要是先有1.spring容器的基本架构 2.spring bean的生命周期 的知识再看下面文章会更好懂。

1.入口

spring核心框架里面一个bean信息注册相关的重要的类

org.springframework.context.annotation.AnnotatedBeanDefinitionReader

它的作用就是通过他,可以使得BeanDefinitionRegistry的类拥有bean类的编程(注解)式注册的能力。

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
//...省略部分代码
//这个方法就是,将那些注解@Component、@Configuration等的解析能力授予给BeanDefinitionRegistry 
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
	}

下面就是registerAnnotationConfigProcessors的源码。

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
			BeanDefinitionRegistry registry, @Nullable Object source) {
		//部分源码
		Set<BeanDefinitionHolder> beanDefs = new LinkedHashSet<>(8);

		if (!registry.containsBeanDefinition(CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME)) {
			RootBeanDefinition def = new RootBeanDefinition(ConfigurationClassPostProcessor.class);
			def.setSource(source);
			beanDefs.add(registerPostProcessor(registry, def, CONFIGURATION_ANNOTATION_PROCESSOR_BEAN_NAME));
		}
}

主要就是ConfigurationClassPostProcessor这个类,这个类就让BeanDefinitionRegistry拥有了处理@Configuration的能力。

2.ConfigurationClassPostProcessor分析

1.最关键的方法postProcessBeanDefinitionRegistry,这个方法对BeanDefinitionRegistry 一些事情, 比如说我要这个BeanDefinitionRegistry 拥有对注解了@Configuration的类的注册能力。

postProcessBeanDefinitionRegistry方法的核心代码processConfigBeanDefinitions();
他主要做了:
1.获取每个有加@Configuration 的BeanDefinition
2.设置各种 beanName生成器
3(最核心).解析每个@Configuration class,注解了@Configuration的类到底要干些什么事情
4.将解析完的配置类信息ConfigurationClass,通过 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions (注册中心注册bean定义。)
5.如果之前没有或者上面类定义信息,就将ImportRegistry注册为bean

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
		List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
		String[] candidateNames = registry.getBeanDefinitionNames();
		//1.获取每个类有加@Configuration 的BeanDefinition
		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 的BeanDefinition 直接返回
		if (configCandidates.isEmpty()) {
			return;
		}
			
		 //2.对@order的进行排序
		configCandidates.sort((bd1, bd2) -> {
			int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
			int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
			return Integer.compare(i1, i2);
		});

		// 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) {
					this.componentScanBeanNameGenerator = generator;
					this.importBeanNameGenerator = generator;
				}
			}
		}

		if (this.environment == null) {
			this.environment = new StandardEnvironment();
		}

		// 3.(最核心的)解析每个@Configuration class, 注解了@Configuration的类到底要干些什么事情(下面重点分析)
		ConfigurationClassParser parser = new ConfigurationClassParser(
				this.metadataReaderFactory, this.problemReporter, this.environment,
				this.resourceLoader, this.componentScanBeanNameGenerator, registry);

		Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
		Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
		do {
			//下面这个就是最最最关键的解析代码
			parser.parse(candidates);
			parser.validate();

			Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
			configClasses.removeAll(alreadyParsed);

			// 4.将解析完的配置类信息ConfigurationClass,通过 ConfigurationClassBeanDefinitionReader.loadBeanDefinitions (注册中心注册bean定义。)
			if (this.reader == null) {
				this.reader = new ConfigurationClassBeanDefinitionReader(
						registry, this.sourceExtractor, this.resourceLoader, this.environment,
						this.importBeanNameGenerator, parser.getImportRegistry());
			}
			this.reader.loadBeanDefinitions(configClasses);
			alreadyParsed.addAll(configClasses);

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

		// 5.如果之前没有或者类配类定义信息,将ImportRegistry注册为bean以支持
		if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
			sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
		}
		
		//6.清除一些缓存信息
		if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
			// Clear cache in externally provided MetadataReaderFactory; this is a no-op
			// for a shared cache since it'll be cleared by the ApplicationContext.
			((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
		}
	}

3.加了@Configuration的类,到底要做些什么事情

主要做的事情:(下面列出来比较重要的,更完整的流程下更下面补充说明)
1.处理配置类的@PropertySource 注解 : 其实就是将@PropertySource 做了那些事情,记录下来。
2.处理配置类的@ComponentScans 注解。扫描这个包的类, 如果有配置类的, 将他们当成配置类处理。
3.处理@Import 注解 。
4.处理@ImportResource
5.处理注解了@Bean的方法

6.记录他的超类, 主要是防止重新处理等一些操作。

以上就是主要做的事情,但是源码里面要做的还不止于此,还要考虑下面的问题
1.首先每个配置类里面还可能包含这内部类,所以对每个加了@Component的内部类注册,如果这个内部类也是配置类。那就要执行上面的操作。
2.然后spring考虑到了 这个类的上级的所有超类。所以递归执行上面的需要做的事情,终止条件就是找不到更上级的超类。
3.@Import 注解,循环Import的问题。
比如 AConfiguration @Import 一个 配置类BConfiguration,BConfiguration然后又 通过@Import AConfiguration 会导致 循环Import的问题。 Spring 是通过 ImportStack 一个栈来确定是否有这个循环Import的问题,(处理AConfiguration 之前先判断栈里面是否有处理AConfiguration ,没有就压栈, 有说明循环Import 了)。有的话就抛处CircularImportProblem错误

整体主要的解析流程:
主要代码再 org.springframework.context.annotation.ConfigurationClassParser#processConfigurationClass
第【1】操作.该类一直到最上面的父类,都进行一下步骤操作(递归的过程)
下面的步骤操作代码主要在:(org.springframework.context.annotation.ConfigurationClassParser#doProcessConfigurationClass)

1. 对该类里面的内部类(不包括父类的) 如果是配置类的 全都从第【1】个操作。 相当于递归。
2. 处理配置类的@PropertySource 注解 : 其实就是将@PropertySource 做了那些事情,记录下来。

3. 处理配置类的@ComponentScans 注解。扫描这个包的类, 如果有配置类的, 将他们当成配置类处理,从第【1】个操作处理。
4. 处理@Import 注解 。
5. 处理@ImportResource
6. 处理注解了@Bean的方法
7. 记录他的超类, 主要是防止重新处理等一些操作。

4.关键解析代码

下面列一下关键的代码 从 上面介绍的 processConfigBeanDefinitions 的 parser.parse(candidates);
完整路径如下:
org.springframework.context.annotation.ConfigurationClassParser#parse(java.util.Set<org.springframework.beans.factory.config.BeanDefinitionHolder>)

public void parse(Set<BeanDefinitionHolder> configCandidates) {
		for (BeanDefinitionHolder holder : configCandidates) {
			BeanDefinition bd = holder.getBeanDefinition();
			try {
			//主要就是parse方法,。
				if (bd instanceof AnnotatedBeanDefinition) {
				//主要是这个, 下面列出的就是这个代码
					parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
				}
				else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
					parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
				}
				else {
					parse(bd.getBeanClassName(), holder.getBeanName());
				}
			}
			catch (BeanDefinitionStoreException ex) {
				throw ex;
			}
			catch (Throwable ex) {
				throw new BeanDefinitionStoreException(
						"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
			}
		}

		this.deferredImportSelectorHandler.process();
	}

进去parse();

protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
		processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
	}

进去processConfigurationClass();

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
		if (this.conditionEvaluator.shouldSkip(configClass.getMetadata(), ConfigurationPhase.PARSE_CONFIGURATION)) {
			return;
		}

		ConfigurationClass existingClass = this.configurationClasses.get(configClass);
		if (existingClass != null) {
			if (configClass.isImported()) {
				if (existingClass.isImported()) {
					existingClass.mergeImportedBy(configClass);
				}
				// Otherwise ignore new imported config class; existing non-imported class overrides it.
				return;
			}
			else {
				// Explicit bean definition found, probably replacing an import.
				// Let's remove the old one and go with the new one.
				this.configurationClasses.remove(configClass);
				this.knownSuperclasses.values().removeIf(configClass::equals);
			}
		}

		//    第【1】操作.该类一直到最上面的父类,都进行一下步骤操作(递归的过程)
		SourceClass sourceClass = asSourceClass(configClass, filter);
		do {
			//进去这个
			sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
		}
		while (sourceClass != null);

		this.configurationClasses.put(configClass, configClass);
	}

进去doProcessConfigurationClass();

protected final SourceClass doProcessConfigurationClass(
			ConfigurationClass configClass, SourceClass sourceClass, Predicate<String> filter)
			throws IOException {

		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
			// a.对该类里面的内部类(不包括父类的) 如果是配置类的 全都从第【1】个操作。 相当于递归。
			processMemberClasses(configClass, sourceClass, filter);
		}

		// 处理配置类的@PropertySource 注解 : 其实就是将@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.info("Ignoring @PropertySource annotation on [" + sourceClass.getMetadata().getClassName() +
						"]. Reason: Environment must implement ConfigurableEnvironment");
			}
		}

		// 处理配置类的@ComponentScans 注解。扫描这个包的类, 如果有配置类的, 将他们当成配置类处理,从第【1】个操作处理。
		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) {
				// The config class is annotated with @ComponentScan -> perform the scan immediately
				Set<BeanDefinitionHolder> scannedBeanDefinitions =
						this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
				// Check the set of scanned definitions for any further config classes and parse recursively if needed
				for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
					BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
					if (bdCand == null) {
						bdCand = holder.getBeanDefinition();
					}
					if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
						parse(bdCand.getBeanClassName(), holder.getBeanName());
					}
				}
			}
		}

		// 处理@Import 注解 。
		processImports(configClass, sourceClass, getImports(sourceClass), filter, true);

		//处理@ImportResource
		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的方法
		Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
		for (MethodMetadata methodMetadata : beanMethods) {
			configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
		}

		// 处理接口的默认方法
		processInterfaces(configClass, sourceClass);

		//g.记录他的超类, 主要是防止重新处理等一些操作。
		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;
	}

其实以上源码所做都是为了准备BeanDefinition, 将BeanDefinition注册到BeanDefinitionRegistry。

有问题欢迎留言讨论~~

@Configuration源码中的具体内容是什么?它的作用是什么? 回答: @Configuration注解是Spring框架中的一个注解,用于标记一个类作为配置类。通过@Configuration注解,可以将该类中声明的bean对象纳入到Spring容器的管理中。@Configuration注解可以与@Component注解一起使用,但是它们之间仍然有一些不同之处。 @Configuration注解的作用是告诉Spring容器,这个类是一个配置类,里面可以包含@Bean注解的方法用于创建bean对象。当Spring容器启动时,会解析@Configuration注解,读取其中的@Bean方法,并将这些方法返回的对象注册到容器中。 @Configuration注解还可以与其他注解一起使用,例如@EnableAutoConfiguration和@ComponentScan等,用于进一步配置Spring应用程序。 具体的@Configuration源码分析可以参考引用和引用中的文章,这些文章深入解析了@Configuration注解的原理和实现细节。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Spring中@Configuration源码深度解析(一)](https://blog.csdn.net/qq_35634181/article/details/104062321)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [spring源码:@Configuration源码](https://blog.csdn.net/CPLASF_/article/details/106840449)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值