Spring源码系列(二)——注册配置类

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    // 这里由于它有父类构造方法,故而先调用父类的构造方法,然后才会调用自己的构造方法
    this();
    register(annotatedClasses);
    refresh();
}

在第一篇文章中,研究了this()中的源码,下面要来探究register(annotatedClasses);这行代码的秘密了。

一、注册配置类

register(annotatedClasses);

这个标题,完全是翻译上面这行代码,下面就慢慢往下分析吧。先贴一下配置类AppConfig的代码,简单哦。

@Configuration
@ComponentScan("com.scorpios")
public class AppConfig {
}

AnnotationConfigApplicationContext类中的register()方法,发现这个方法可以传多个配置类。

/**
* 这个方法可以注册单个Bean给容器,比如有新加的类可以用这个方法
* 但是注册注册之后需要手动调用refresh()方法去触发容器解析注解
* 有两个作用:
* 1.可以注册一个配置类
* 2.还可以单独注册一个bean
*/
public void register(Class<?>... annotatedClasses) {
    // 这个reader读取器,就是在上面创建容器时无参构造器中创建的reader!
    this.reader.register(annotatedClasses);
}

// 如果传入的是多个配置类,则要进行循环
public void register(Class<?>... annotatedClasses) {
    for (Class<?> annotatedClass : annotatedClasses) {
        // 把配置类转化为BeanDefinition放入到beanDefinitionMap中
        registerBean(annotatedClass);
    }
}

在这里插入图片描述

二、注册Bean

下面来研究下AnnotatedBeanDefinitionReader中的registerBean(annotatedClass);这个方法。

// 这个方法就是将一个类转化为一个BeanDefinition,给BeanDefinition里面的属性确定值
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
		@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {

	/**
	 * 根据指定的Class创建一个AnnotatedGenericBeanDefinition,AnnotatedGenericBeanDefinition包含了类的其他信息,
	 * 比如一些元信息 scope,lazy等等
	 * annotatedClass: com.scorpios.app.AppConfig
	 */
	AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);

	// 判断这个类是否需要跳过解析,通过代码可以知道spring判断是否跳过解析,主要判断类有没有加特定注解
	if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
		return;
	}

	// 不知道
	abd.setInstanceSupplier(instanceSupplier);
	// 得到类的作用域
	ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
	// 把类的作用域添加到数据结构结构中
	abd.setScope(scopeMetadata.getScopeName());
	// 通过beanNameGenerator生成类的名字,
    // 这地方是根据ClassName来截取的类名:com.scorpios.app.AppConfig
	String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));


	// 此处是处理类当中的通用注解,分析源码可以知道主要处理Lazy、Primary、DependsOn、Role、Description等注解
	AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

	/**
	 * 如果在向容器注册注解Bean定义时,使用了额外的限定符注解则解析
	 * 关于Qualifier和Primary注解,主要涉及到Spring的自动装配
	 * 这里需要注意的:
	 * byName和qualifiers这个变量是Annotation类型的数组,里面存不仅仅是Qualifier注解
	 * 理论上里面里面存的是一切注解,所以可以看到下面的代码Spring去循环了这个数组
	 * 然后依次判断了注解当中是否包含了Primary,是否包含了Lazy
	 */
    // 此参数是方法传入的,永远为空,如何给一个Bean传入Primary属性呢?两个方式,一个是加@Primary注解,一个就是往qualifiers中添加Primary
	if (qualifiers != null) {
		for (Class<? extends Annotation> qualifier : qualifiers) {
			// 如果配置了@Primary注解,如果加了则作为首选
			if (Primary.class == qualifier) {
				abd.setPrimary(true);
			} else if (Lazy.class == qualifier) {// 懒加载
				abd.setLazyInit(true);
			} else {
				// 如果使用了除@Primary和@Lazy以外的其他注解,则为该Bean添加一个根据名字自动装配的限定符
				abd.addQualifier(new AutowireCandidateQualifier(qualifier));
			}
		}
	}
    // 忽略
	for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
		customizer.customize(abd);
	}

	// 这个BeanDefinitionHolder也是一个数据结构
	BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
	// ScopedProxyMode 这个知识点比较复杂,需要结合web去理解
	definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    
	/**
	 * 把上述的这个数据结构注册给registry(AnnotationConfigApplicationContext)
	 * registerBeanDefinition里面就是把definitionHolder这个数据结构包含的信息注册到DefaultListableBeanFactory这个工厂
	 */
	BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

三、小结

这个方法执行完,beanDefinitionMap中共有7个BeanDefinition对象,分别是之前创建读取器Reader时,Spring容器自己添加的6个,加上这个register(annotatedClasses);添加的一个。

见下图:

在这里插入图片描述
在这里插入图片描述
这里再强调一个概念,Spring容器需要将Class类转化成BeanDefinition,最后Spring容器是根据这个BeanDefinition来创建实例的。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

止步前行

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值