接上篇
3 reader 注册配置类
该 part 的起点:
public AnnotationConfigApplicationContext(Class<?>… annotatedClasses) {
this();
register(annotatedClasses); // 3 reader 注册配置类
refresh();
}
该行代码会将 iocConfig bean 注册到 reader 中 AnnotationConfigApplicationContext 的 register 方法:
//AnnotationConfigApplicationContext.class
public void register(Class<?>… annotatedClasses) {
// 参数非空效验
Assert.notEmpty(annotatedClasses, “At least one annotated class must be specified”);
// 调用 AnnotatedBeanDefinitionReader 的 register 方法
this.reader.register(annotatedClasses);
}
上述方法主要是调用了 AnnotatedBeanDefinitionReader 的 register 方法:
//AnnotatedBeanDefinitionReader.class
public void register(Class<?>… annotatedClasses) {
for (Class<?> annotatedClass : annotatedClasses) {
registerBean(annotatedClass);
}
}
上述方法循环调用了 AnnotatedBeanDefinitionReader 的 registerBean 方法:
//AnnotatedBeanDefinitionReader.class
public void registerBean(Class<?> annotatedClass) {
doRegisterBean(annotatedClass, null, null, null);
}
上述方法调用了 AnnotatedBeanDefinitionReader 的 doRegisterBean 方法,这个方法比较长,需要重点关注:
//AnnotatedBeanDefinitionReader.class
<T> void doRegisterBean(Class<T> annotatedClass, @Nullable Supplier<T> instanceSupplier, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, BeanDefinitionCustomizer… definitionCustomizers) {
// 用 BeanDefinition 包装 iocConfig
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(annotatedClass);
// 此段代码用于处理 Conditional 注解,在特定条件下阻断 bean 的注册
// 本例中此处不会 return
//3.1
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
// 用来创建 bean 的 supplier,会替代掉 bean 本身的创建方法
//instanceSupplier 一般情况下为 null
abd.setInstanceSupplier(instanceSupplier);
// 此行代码处理 scope 注解,本例中 scope 是默认值 singleton
//3.2
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
//bean name 在本例中为自动生成的 iocConfig
//3.3
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
// 特定注解解析,本例中均不做操作
//3.4
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
// 本例中 qualifiers 传入的是 null
//3.5
if (qualifiers != null) {
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}
else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}
else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
// 本例中 definitionCustomizers 传入的是 null
//3.6
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
// 用 BeanDefinitionHolder 包装 BeanDefinition
BeanDefinitionHolder definitionHolder
= new BeanDefinitionHolder(abd,beanName);
// 此行代码与动态代理和 scope 注解有关,但是在本案例中没有做任何操作,只是返回了传入的 definitionHolder
//3.7
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//iocConfig 注册
// 3.8
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
3.1
看一下上述方法的片段:
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
首先需要了解到 abd 的 getMetadata() 方法会获取到 abd 中的 metadata 对象。
该对象是一个 StandardAnnotationMetadata 的实例化对象,在创建的时候会利用 java.Class 中的 api 获取 bean 中所有的注解,并保存为一个数组:
//StandardAnnotationMetadata.class
public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
// 此处的 introspectedClass 即为 bean 的 class
// 父类的构造器用于内部保存 bean 的 class
super(introspectedClass);
// 获取所有的注解
this.annotations = introspectedClass.getAnnotations();
//nestedAnnotationsAsMap 暂时用不上,按下不表
//nestedAnnotationsAsMap = true
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
}
conditionEvaluator 是一个注解解析器,在 AnnotatedBeanDefinitionReader 创建的时候在其构造方法内被创建:
this.conditionEvaluator = new ConditionEvaluator(registry, environment, null);
追踪 conditionEvaluator 的 shouldSkip(…) 方法:
//ConditionEvaluator.class
public boolean shouldSkip(AnnotatedTypeMetadata metadata) {
return shouldSkip(metadata, null); // 调用自身的重载方法
}
//ConditionEvaluator.class
public boolean shouldSkip(@Nullable AnnotatedTypeMetadata metadata, @Nullable ConfigurationPhase phase) {
//metadata 在此处不为 null
// 判断 bean 是否使用了 Conditional 注解
if (metadata == null || !metadata.isAnnotated(Conditional.class.getName())) {
// 如果 metadata 为空或者 bean 没有使用 Conditional 注解,就会返回 false
return false;
}
// 第一次调用该方法的时候,phase 为 null
if (phase == null) {
// 下列源码规整一下,其实是四个条件:
//1 bean.metadata 是 AnnotationMetadata 或其子类
//2 bean 使用了 Configuration 注解
//3 bean 不是一个接口
//4 bean 使用了 Component、ComponentScan、Import、ImportResource 这四个注解之一,或者使用了 Bean 注解
// 这四个条件中满足 1、2 或者 1、3、4 就会进入 if 语句中
// 请注意,对于 config bean 来说,只要使用了 Conditional 注解,必然会进入到语句中
if (metadata instanceof AnnotationMetadata &&
ConfigurationClassUtils.isConfigurationCandidate((AnnotationMetadata) metadata)) {
return shouldSkip(metadata, ConfigurationPhase.PARSE_CONFIGURATION);
}
return shouldSkip(metadata, ConfigurationPhase.REGISTER_BEAN);
}
List<Condition> conditions = new ArrayList<>();
//getConditionClasses(metadata) 会获取到 Conditional 注解中的 value 数组
for (String[] conditionClasses : getConditionClasses(metadata)) {
// 遍历数组
for (String conditionClass : conditionClasses) {
// 利用反射获取实例化数组内的 class
Condition condition = getCondition(conditionClass, this.context.getClassLoader());
conditions.add(condition); // 获取所有的 canditionClass 并以次存入到列表中
}
}
// 利用了 List 自带的排序 api 进行排序
AnnotationAwareOrderComparator.sort(conditions);
for (Condition condition : conditions) {
ConfigurationPhase requiredPhase = null;
if (condition instanceof ConfigurationCondition) {
requiredPhase = ((ConfigurationCondition) condition).getConfigurationPhase();
}
// 对于 Conditional 内的 value 并非是实现 ConfigurationCondition 接口的 class,requiredPhase == null 必然为 true;对于实现了该接口的 class,requiredPhase == phase 必然为 true
// 所以要注意,如果 value class 的 matches(…) 方法返回 false,则会在此处阻断 bean 的注册
if ((requiredPhase == null || requiredPhase == phase) && !condition.matches(this.context, metadata)) {
return true;
}
}
// 正常情况下,做完所有检查工作之后还是会返回 false
return false;
}
可以看到这个方法其实是 Conditional 注解的解析器,对于未使用这个注解的 bean,直接就返回了,不会继续往下走。
先来看一下 Conditional 的源码:
@Target({ElementType.TYPE, ElementType.METHOD}) // 可以标注在类和方法上方
@Retention(RetentionPolicy.RUNTIME) // 注解生命周期
@Documented //javadoc 相关
public @interface Conditional {
//class 数组
// 这个数组里的值必须要是实现了 Condition 接口的类
// 注意这个 value 没有默认值,如果要使用该注解就必须要填入
Class<? extends Condition>[] value();
}
顺便来看一下 Condition 接口:
public interface Condition {
// 这个方法会返回一个 boolean 值,如果为 true,则将继承该接口的类注入到 Conditional 修饰的 bean 中
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
conditional 的具体内容有待研究,不展开。
3.2
看下方代码片段:
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
scopeMetadataResolver 是一个定义在 AnnotatedBeanDefinitionReader 里的 AnnotationScopeMetadataResolver 对象。顾名思义,其主要作用是解析 scope 标签。
先来看一下 Scope 注解的定义源码:
@Target({ElementType.TYPE, ElementType.METHOD}) // 可以标注在类和方法上方
@Retention(RetentionPolicy.RUNTIME) // 注解生命周期
@Documented //javadoc 相关
public @interface Scope {
//value 是平时开发中最常用到的 scope 属性,用来设置是否是单例模式
// 在处理注解的时候 value 属性会被转化成 scopeName 属性来看待
// 所以两个属性其实是一样的
String value() default “”;
String scopeName() default “”;
// 代理模式设置,默认为无代理
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
ScopedProxyMode 是一个枚举类,没有任何处理业务逻辑的代码,一同放在这里:
public enum ScopedProxyMode {
DEFAULT, // 不使用代理,default 和 no 是等价的
NO,
INTERFACES, // 使用 jdk 自带的动态代理 api 进行创建
TARGET_CLASS; //target-class 模式,需要使用 cglib 进行 bean 的创建
}
AnnotationScopeMetadataResolver 的 resolveScopeMetadata(…) 方法具体实现如下:
//AnnotationScopeMetadataResolver.class
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
// 创建一个 metadata 对象用于返回
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
// 从 bean 的注解里寻找 scope 这个注解
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
// 如果 bean 确实是用了 scope 注解
if (attributes != null) {
metadata.setScopeName(attributes.getString(“value”)); // 存入 scope 的 value 属性值
// 获取 proxyMode 属性值
ScopedProxyMode proxyMode = attributes.getEnum(“proxyMode”);
//default 和 no 是等同的,默认会转化成 no 进行处理
if (proxyMode == ScopedProxyMode.DEFAULT) {
//this.defaultProxyMode = ScopedProxyMode.NO
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode); // 存入 scope 的 proxyMode 属性值
}
}
// 没有使用 scope 的情况下会返回一个新建的 metadata
return metadata;
}
annDef.getMetadata() 会获取到一个 AnnotationMetadata 对象,里面包含了 bean 的所有注解信息。
scopeAnnotationType 是一个定义在 AnnotationScopeMetadataResolver 里的 Class 对象:
protected Class<? extends Annotation> scopeAnnotationType = Scope.class;
可见 AnnotationConfigUtils 的 attributesFor(…) 就是去注解集里查找 scope 注解,并且封装成一个 AnnotationAttributes 返回。AnnotationAttributes 是 Spring 用来存储注解所定义的一种数据结构,本质上是一个 LinkedHashMap。
再回到本小节最上方的代码:
abd.setScope(scopeMetadata.getScopeName());
最后其实 BeanDefinition 只接收了 scopeName,而没有接收 proxyMode。proxyMode 属性会在后面代码中用到。
3.3
看下方代码片段:
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
beanNameGenerator 是一个定义在 AnnotatedBeanDefinitionReader 里的 AnnotationBeanNameGenerator 对象,顾名思义用来生成 bean 的名称:
private BeanNameGenerator beanNameGenerator = new AnnotationBeanNameGenerator();
追踪一下 generateBeanName(…) 方法:
//AnnotationBeanNameGenerator.class
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
//determineBeanNameFromAnnotation(…) 方法会从 bean 的所有注解里去遍历搜寻 bean 名称
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
// 如果此处的 beanName 非空,则表明在注解里找到了定义的 bean 名称
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// 没有在前面 return,证明 bean 没有被设置名称,则在此处默认生成一个名称
return buildDefaultBeanName(definition, registry);
}
看一眼 buildDefaultBeanName(…) 方法:
//AnnotationBeanNameGenerator.class
protected String buildDefaultBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
return buildDefaultBeanName(definition);
}
其实这个方法只用到了 definition,而没有使用到传入的 registry。
继续追踪代码实现:
//AnnotationBeanNameGenerator.class
protected String buildDefaultBeanName(BeanDefinition definition) {
// 该处返回的是 bean 的整个 class 路径和名称
String beanClassName = definition.getBeanClassName();
//beanClassName 非空判断
Assert.state(beanClassName != null, “No bean class name set”);
// 截掉 class 的路径,只取 class 名称
String shortClassName = ClassUtils.getShortName(beanClassName);
// 将首字母小写并返回
return Introspector.decapitalize(shortClassName);
}
3.4
看下方代码实现:
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
追踪这行代码:
//AnnotationConfigUtils.class
public static void processCommonDefinitionAnnotations(AnnotatedBeanDefinition abd) {
// 调用重载方法
processCommonDefinitionAnnotations(abd, abd.getMetadata());
}
//AnnotationConfigUtils.class
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) {
// 这里还有一个补充检查,如果传入的 metadata 不是 abd 内部的 metadata 的话,还会继续进来判断一次
// 在本例中没什么必要
lazy = attributesFor(abd.getMetadata(), Lazy.class);
if (lazy != null) {
abd.setLazyInit(lazy.getBoolean(“value”));
}
}
// 检查 primary 注解
if (metadata.isAnnotated(Primary.class.getName())) {
abd.setPrimary(true);
}
// 检查 dependsOn 注解
AnnotationAttributes dependsOn = attributesFor(metadata, DependsOn.class);
if (dependsOn != null) {
abd.setDependsOn(dependsOn.getStringArray(“value”));
}
// 检查 role 注解
AnnotationAttributes role = attributesFor(metadata, Role.class);
if (role != null) {
abd.setRole(role.getNumber(“value”).intValue());
}
// 检查 description 注解
AnnotationAttributes description = attributesFor(metadata, Description.class);
if (description != null) {
abd.setDescription(description.getString(“value”));
}
}
其实上述代码的主体都是类似的,步骤都是尝试从 metadata 中获取特定注解,如果获取到了就将其作为一个属性值 set 进 abd 中。
这里需要强调 abd 就是要注册的 bean 的 BeanDefinition 包装对象。
本例中没有用到上述的注解,所以均为 null。
3.5
看下方代码:
if (qualifiers != null) {
// 在 qualifiers 不为 null 的情况下会遍历该集合,并将当中的所有的元素解析出来,进行业务操作
for (Class<? extends Annotation> qualifier : qualifiers) {
if (Primary.class == qualifier) {
abd.setPrimary(true);
}else if (Lazy.class == qualifier) {
abd.setLazyInit(true);
}else {
abd.addQualifier(new AutowireCandidateQualifier(qualifier));
}
}
}
上述代码是针对 qualifier 注解的解析,和 3.4 很类似。
AutowireCandidateQualifier 是注解的包装类,储存了一个特定注解的名字和 value。abd 的 addQualifier(…) 方法会将这个创建出来的包装类存储到一个 map 对象里。
3.6
看下方代码:
for (BeanDefinitionCustomizer customizer : definitionCustomizers) {
customizer.customize(abd);
}
这段代码是 Spring5 中新加入的。根据注释,官方应该是留下这个接口用以让开发者通过 lambda 表达式去定义 bean。
3.7
看下方代码:
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
先来追踪 applyScopedProxyMode(…) 方法:
//AnnotationConfigUtils.class
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
// 先判断 scope 注解的使用
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
// 判断具体使用哪种模式
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
// 此行代码会连向 spring-aop 包下的类来处理
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
注意,此处传入的 metadata 是上述 3.2 小节中新建出来并返回的对象:
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
对于一般没有使用 scope 注解或者 scope 注解为默认的 bean,此时 scopedProxyMode 是等于 ScopedProxyMode.NO 的。
对于 scopedProxyMode 不为 NO 的 bean,均为需要使用动态代理进行创建的对象,区别只是使用 jdk 自带的 api 还是使用 cglib 包。
追踪一下 ScopedProxyCreator 的 createScopedProxy(…) 方法:
//ScopedProxyCreator.class
public static BeanDefinitionHolder createScopedProxy(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}
继续追踪:
//ScopedProxyUtils.class
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
//bean 的名称
String originalBeanName = definition.getBeanName();
//bean 的 BeanDefinition 包装类
BeanDefinition targetDefinition = definition.getBeanDefinition();
// 在 bean 的名称前面加上字符串 “scopedTarget.”,拼成 targetBeanName
// 比如 scopedTarget.iocConfig
String targetBeanName = getTargetBeanName(originalBeanName);
// 以下代码用来组装一个动态代理的工厂 bean,这个 bean 是用来动态代理的主体
RootBeanDefinition proxyDefinition = new RootBeanDefinition(ScopedProxyFactoryBean.class);
proxyDefinition.setDecoratedDefinition(new BeanDefinitionHolder(targetDefinition, targetBeanName));
proxyDefinition.setOriginatingBeanDefinition(targetDefinition);
proxyDefinition.setSource(definition.getSource());
proxyDefinition.setRole(targetDefinition.getRole());
proxyDefinition.getPropertyValues().add(“targetBeanName”, targetBeanName);
if (proxyTargetClass) {
targetDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
}else {
proxyDefinition.getPropertyValues().add(“proxyTargetClass”, Boolean.FALSE);
}
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// 此处的 targetDefinition 是传入的 bean 的包装类
// 这一步会提前将该 bean 进行注册
// 注册过程见 2.2
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// 返回的其实是动态代理所需要的工厂 bean
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
scope 的具体内容有待研究,不展开。
3.8
在上例代码中的这一行中:
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
传入的 definitionHolder 就是 iocConfig bean 的包装对象;而传入的 registry 就是在 ApplicationContext 中实例化的 BeanFactory,此处具体而言就是 DefaultListableBeanFactory。
继续追踪这行代码的内部实现:
//BeanDefinitionReaderUtils.class
public static void registerBeanDefinition(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
throws BeanDefinitionStoreException {
// 获取 bean 的名称
String beanName = definitionHolder.getBeanName();
// 调用 AnnotationConfigApplicationContext 的 registerBeanDefinition 方法
// 注册过程见 2.2
registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
// 处理 bean 的别名,本例中没有别名,不进入循环
String[] aliases = definitionHolder.getAliases();
if (aliases != null) {
for (String alias : aliases) {
registry.registerAlias(beanName, alias);
}
}
}
alias 的具体内容有待研究,不展开。
到此为止,iocConfig bean 已经被注册到 bean factory 中。
To Be Continued …