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
来创建实例的。