上一章总结到,AnnotationConfigApplicationContext提供两种方式注册bean,一是注册指定的bean,二是扫描指定的包。本章主要描述前者的过程。

注册指定的bean

AnnotatedBeanDefinitionReader.register()向容器注册指定bean。该方法完成整个过程的调用,其总结步骤如下

  1. 解析元数据信息,如作用域
  2. 对bean定义的通用注解处理
  3. 对qualifiers数据处理
  4. 根据作用域创建代理对象
  5. 注册BeanDefinition
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
public void register(Class<?>... annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}

<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer... definitionCustomizers) {
// 创建BeanDefinition的实现对象,用于封装配置信息
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}

abd.setInstanceSupplier(instanceSupplier);
// 解析作用域,例如@Scoper("singleton")
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
// 保存到BeanDefinition对象中
abd.setScope(scopeMetadata.getScopeName());
// 为bean生成名字
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));

// 处理通用bean定义注解,如@Lazy、@Primary
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 对@Qualifier处理,如果自动装配配置了该注解,则使用该注解名字进行装配
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
// 如果配置了@Primary,则使用该bean进行注入
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
// 如果配置了@Lazy,则设置延迟加载
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
// 如果不是@Primary、@Lazy注解,则为bean添加自动装配时的限定符,既:根据名字进行装配
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 将BeanDefinition封装成Holder对象,用于方便注册。
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//根据bean的作用域(singleton、prototype) 创建代理对象
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
// 像IOC注册BeanDefinition
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

解析元数据信息

该过程由AnnotationScopeMetadataResolver.resolveScopeMetadata()实现,主要用于解析bean是原生类型(prototype)还是单例类型(singleton)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
// annDef.getMetadata()在AnnotatedBeanDefinition构造中初始化的,用数组存储着bean所标注的注解,管理着所有注解和注解的值.
// 从所有的注解中获取scope的值,即@Scope注解的值
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
// 将Scope中的值保存到返回值中
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}

处理通用注解

这里为啥叫通用注解,我其实觉得不太合适,我就是英文直译过来的。因为在我看来通用注解不应该只包含@Lazy、@Primary、@DependsOn。或者从某个角度来说,所有注解都应该通用。不过好像除了通用能简单描述一下,好像也没有其他更合适的词了。

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
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}

static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd, AnnotatedTypeMetadata metadata) {
// 处理@Lazy注解
AnnotationAttributes lazy = attributesFor(metadata, Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
} else if (abd.getMetadata() != metadata) {
// 这里我选择的这个流程,通过重载方法进来的,二者一定相等。
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean("value"));
}
}

// 处理@Primary注解,标记自动装配时首选该bean
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
// @DependsOn注解,用于标注该bean所依赖的其他bean
// 在实例化该bean之前,spring会先实例化它所依赖的bean
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray("value"));
}

if (abd instanceof AbstractBeanDefinition) {
AbstractBeanDefinition absBd = (AbstractBeanDefinition) abd;
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
absBd.setRole(role.getNumber("value").intValue());
}
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
absBd.setDescription(description.getString("value"));
}
}
}

根据作用域创建代理对象

这个方法存在的意义是为了区分使用jdk代理还是cglib代理,这里主要为引入AOP埋下伏笔,主要还是在AOP中使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {

// 刚刚所获取的元数据信息
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
// 如果proxy-mode的值为NO,表示不需要代理
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
// 判断设置的值是TARGET_CLASS,还是INTERFACES
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 根据是为INTERFACES,判断使用JDK动态代理还是CGLIB来生成代理对象
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}

注册BeanDefinition

向IOC中注册BeanDefinition跟XML一样,都调用的是BeanDefinitionReaderUtils.registerBeanDefinition()。spring源码之IOC - xml - 注册BeanDefinition

总结

整体来说,注解配置bean比XML要简单,在spring内部实现也要简单。没有复杂的xml解析过程,对应的Class属性值、id、name,都能直接获取的到,然后将其保存在BeanDefinition中,并注册IOC就完成了容器启动。