【栖梧-源码-spring】@Bean从解析到注册到beanDefinitionMap

序幕

本文是我的第一篇博客,自我研读spring源码以来,收获颇丰。自工作以来,疑惑颇多,于是通过网络、同事、领导、技术网友等益友的分享和指导,解决了工作中许多疑难杂症,所以我也非常希望把我工作中、学习中的收获分享给所有需要的人。同时受水平所限,其中必有缺漏不足之处,还望指出。

"道友"解释->志同道合者;

源码阅读技巧

书山有路勤为径,学海无涯需持久!
源码阅读是一件枯燥乏味的事情,这种说法是对没有时间、没有兴趣、没有好奇心的道友来讲的。要想深入理解一个框架的原理,必须了解其实现细节,所以花费大量的时间、精力来吸取里面的营养是必须的。

<源码-spring>系列文章均涉及大量源码,且自建简单的项目是基于springboot 2的版本,如果其他版本的源码可能稍有差异,属正常情况。
如果道友你从来没有看过spring源码,阅读起来将会吃力,请悉知!

本文说明

本文核心讲解的是@Bean注解从解析bean到beanFactory的beanDefiniton中

类 ConfigurationClassParser#doProcessConfigurationClass

package org.springframework.context.annotation;

当spring启动后,走到高级AbstractApplicationContext这个高级容器的最核心的 refresh() 方法后,再进入invokeBeanFactoryPostProcessors(beanFactory)调用后置处理器方法,就会调用静态方法PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()) 开始解析所有的BeanDefinition了,由于本文主要讲解@Bean,所以其他的暂时不详解。

	//此类就是解析配置类的入口
	@Nullable
	protected final SourceClass doProcessConfigurationClass(ConfigurationClass configClass, SourceClass sourceClass)
			throws IOException {
		//先判断是否有@Component注解,
		if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
		    //首先递归处理任何成员(嵌套)类
			// Recursively process any member (nested) classes first
			processMemberClasses(configClass, sourceClass);
		}
		//处理带有@PropertySource的类,然后将里面变量存到全局的Environment中去
		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");
			}
		}

		// 处理 @ComponentScan 注解,注意里面是多个递归解析(如果不清楚是递归的道友进入这个方法可能会晕掉的),这
		//里面就会解析所有的@Component注解的,包括@Controller、@Service等这些被@Component注解过的注解,解析后的
		//bean全部放到ConfigurationClassParser这个对象的 configurationClasses 这个map里面进行后续处理
		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), true);

		// Process any @ImportResource annotations
		AnnotationAttributes importResource =
				AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);
		if (importResource != null) {
			String[] resources = importResource.getStringArr
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值