AnnotationConfigApplicationContext 源码分析(二):注册配置类
本文是作者的个人学习笔记,仅做参考,Spring代码版本5.2.2
AnnotationConfigApplicationContext 源码分析(一)
注册配置类
注册配置类将要解析由AnnotationConfigRegistry接口所提供的#register(Class<?>... componentClasses)方法,该方法用于注册一个或多个组件类(标注了@component的类),注意的是注册完了之后容器必须调用#refresh()方法,不然将会导致未知的问题。
public class AnnotationConfigApplicationContext extends GenericApplicationContext implements AnnotationConfigRegistry {
/**
* Register one or more component classes to be processed.
* <p>Note that {@link #refresh()} must be called in order for the context
* to fully process the new classes.
* @param componentClasses one or more component classes — for example,
* {@link Configuration @Configuration} classes
*
* 注册一个或多个要处理的组件类。
* <p>请注意,必须调用{@link #refresh()},以便容器完全处理新类。
* @param componentClasses 一个或多个组件类,例如,{@link Configuration@Configuration}类
*/
@Override
public void register(Class<?>... componentClasses) {
Assert.notEmpty(componentClasses, "At least one component class must be specified");
this.reader.register(componentClasses);
}
}
根据代码可以知道,实际上调用的是AnnotatedBeanDefinitionReader#register(Class<?>... componentClasses)方法
public class AnnotatedBeanDefinitionReader {
/**
* Register one or more component classes to be processed.
* <p>Calls to {@code register} are idempotent; adding the same
* component class more than once has no additional effect.
* @param componentClasses one or more component classes,
* e.g. {@link Configuration @Configuration} classes
*
* 注册一个或多个要处理的组件类。
* <p>对{@code register}的调用是等幂的;多次添加同一个组件类没有额外的效果。
* @param componentClasses 一个或多个组件类,例如{@link Configuration @Configuration}类
*/
public void register(Class<?>... componentClasses) {
for (Class<?> componentClass : componentClasses) {
registerBean(componentClass);
}
}
public void registerBean(Class<?> beanClass) {
doRegisterBean(beanClass, null, null, null, null);
}
}
for循环依次调用注册组件类,这里就不过多解析
public class AnnotatedBeanDefinitionReader {
/** **/
private ScopeMetadataResolver scopeMetadataResolver = new AnnotationScopeMetadataResolver();
/**
* Register a bean from the given bean class, deriving its metadata from
* class-declared annotations.
* @param beanClass the class of the bean
* @param name an explicit name for the bean
* @param qualifiers specific qualifier annotations to consider, if any,
* in addition to qualifiers at the bean class level
* @param supplier a callback for creating an instance of the bean
* (may be {@code null})
* @param customizers one or more callbacks for customizing the factory's
* {@link BeanDefinition}, e.g. setting a lazy-init or primary flag
*
* 从给定的bean类中注册一个bean,从类声明的注释中派生其元数据。
* @param beanClass 注册的Bean的Class对象
* @param name bean的显式名称
* @param qualifiers 除了bean类级别的限定符之外,要考虑的特定限定符注释(如果有的话)
* @param supplier 用于创建bean实例的回调(可以是{@code null})
* @param customizers 一个或多个回调,用于自定义工厂的{@link BeanDefinition},例如设置lazy init或primary标志
* @since 5.0
*/
private <T> void doRegisterBean(Class<T> beanClass, @Nullable String name,
@Nullable Class<? extends Annotation>[] qualifiers, @Nullable Supplier<T> supplier,
@Nullable BeanDefinitionCustomizer[] customizers) {
//1、根据beanClass生成AnnotatedGenericBeanDefinition
AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
//2、
if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
return;
}
//3、supplier==null,略
abd.setInstanceSupplier(supplier);
//4、解析BeanDefinition上的@Scope标签,设置BeanDefinition的scope
ScopeMetadata scopeMetadata = this.scopeMetadataResolver.resolveScopeMetadata(abd);
abd.setScope(scopeMetadata.getScopeName());
//5、解析BeanDefinition获得beanName(Bean的名称)
String beanName = (name != null ? name : this.beanNameGenerator.generateBeanName(abd, this.registry));
//6、分析类上的多个注解,在BeanDefinition上设置注解上设置的配置元数据
AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);
//7、qualifiers==null,略
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));
}
}
}
//8、customizers==null,略
if (customizers != null) {
for (BeanDefinitionCustomizer customizer : customizers) {
customizer.customize(abd);
}
}
//9、生成BeanDefinitionHolder对象
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(abd, beanName);
//10、作用域代理策略,针对@Scope标签的proxyMode属性
definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
//11、注册definitionHolder到容器中
BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}
}
往容器中注册一个bean
参数解析:
- beanClass:解析的目标类
- name:这里为空,注册的名字
- qualifiers:这里为空,暂不分析
- supplier:这里为空,暂不分析
- customizers:这里为空,暂不分析
步骤:
- 生成AnnotatedGenericBeanDefinition对象(存储Bean的描述信息的对象),持有beanClass,同时解析beanClass获取部分配置元数据(配置元数据即描述这个Bean的配置信息),存储到该BeanDefinition对象中;
- 暂时跳过;
- 这里无作用,略;
- 使用scopeMetadataResolver解析BeanDefinition上的@Scope标签,确定作用域元数据。然后设置到BeanDefinition上
- 解析BeanDefinition获得beanName(Bean的名称)
- 通过AnnotatedBeanDefinition上的配置元数据,解析存储在该配置元数据上的以下的注解信息,获取注解上的值,存储到该AnnotatedBeanDefinition对象上
- @Lazy
- @Primary
- @DependsOn
- @Role
- @Description
- 这里无作用,略;
- 这里无作用,略;
- 生成BeanDefinitionHolder对象,持有BeanDefinition和Bean的名称
- 作用域代理策略,将根据参数判断是否需要代理,使用jdk代理还是CGLIB代理
- 往容器中注册BeanDefinitionHolder
生成AnnotatedGenericBeanDefinition对象
public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
/**
* Create a new AnnotatedGenericBeanDefinition for the given bean class.
* @param beanClass the loaded bean class
* 为给定的bean类创建一个新的AnnotatedGenericBeanDefinition。
* @param beanClass 加载的bean类
*/
public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
setBeanClass(beanClass);
this.metadata = AnnotationMetadata.introspect(beanClass);
}
}
这个类是GenericBeanDefinition(GenericBeanDefinition是通用的BeanDefinition)的基础上实现AnnotatedBeanDefinition接口,该接口提供了用于暴露注解相关的配置元数据,即AnnotationMetadata的接口。
AnnotatedGenericBeanDefinition类型的BeanDefinition通常只在注册组件类的时候被定义。
步骤:
1. BeanDefinition持有类对象
2. 通过内省(java机制)类对象生成StandardAnnotationMetadata对象(配置元数据对象)并被当前BeanDefinition持有。相关类将另起文章分析
解析BeanDefinition获取ScopeMetadata
/**
* A {@link ScopeMetadataResolver} implementation that by default checks for
* the presence of Spring's {@link Scope @Scope} annotation on the bean class.
*
* <p>The exact type of annotation that is checked for is configurable via
* {@link #setScopeAnnotationType(Class)}.
* 默认情况下检查bean类上是否存在Spring的{@link Scope@Scope}注释的{@link ScopeMetadataResolver}实现。
* <p>检查的注释的确切类型可以通过{@link #setScopeAnnotationType(Class)}配置
*/
public class AnnotationScopeMetadataResolver implements ScopeMetadataResolver {
@Override
public ScopeMetadata resolveScopeMetadata(BeanDefinition definition) {
ScopeMetadata metadata = new ScopeMetadata();
if (definition instanceof AnnotatedBeanDefinition) {
AnnotatedBeanDefinition annDef = (AnnotatedBeanDefinition) definition;
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(
annDef.getMetadata(), this.scopeAnnotationType);
if (attributes != null) {
metadata.setScopeName(attributes.getString("value"));
ScopedProxyMode proxyMode = attributes.getEnum("proxyMode");
if (proxyMode == ScopedProxyMode.DEFAULT) {
proxyMode = this.defaultProxyMode;
}
metadata.setScopedProxyMode(proxyMode);
}
}
return metadata;
}
}
步骤:
- 新建ScopeMetadata对象
- 使用AnnotationConfigUtils工具类获取标记了@Scope的注解对象(AnnotationAttributes)
- 如果注解对象不为空,则解析注解对象的属性,并设置给配置ScopeMetadata(保存Scope注解信息的配置元数据)
- value—>setScopeName
- proxyMode—>设置setScopedProxyMode:作用域代理模式,用于决定是否要代理这个类,代理的模式是jdk代理还是CGLIB代理
- 返回ScopeMetadata对象后,通过BeanDefinition#setScope(String scopeName)设置到BeanDefinition中持有
生成BeanName策略
public class AnnotationBeanNameGenerator implements BeanNameGenerator {
public String generateBeanName(BeanDefinition definition, BeanDefinitionRegistry registry) {
if (definition instanceof AnnotatedBeanDefinition) {
String beanName = determineBeanNameFromAnnotation((AnnotatedBeanDefinition) definition);
if (StringUtils.hasText(beanName)) {
// Explicit bean name found.
return beanName;
}
}
// Fallback: generate a unique default bean name.
return buildDefaultBeanName(definition, registry);
}
}
BeanNameGenerator是Spring中为bean definitions生成名字策略接口。
AnnotationBeanNameGenerator生成BeanName的策略:
- 如果definition是AnnotatedBeanDefinition,则会通过解析类上的注解,获取以下注解(包括继承的注解类)上value的值作为BeanName
- @Component
- @ManagedBean
- @Named
- 如果以上注解中value的值为null,将会获取类名,转化为beanName,转换方式如下
- 常规类:package.MyConfiguration—>myConfiguration
- 静态内部类:package.MyConfiguration$Config—>myConfiguration.Config
作用域代理策略
public abstract class AnnotationConfigUtils {
static BeanDefinitionHolder applyScopedProxyMode(
ScopeMetadata metadata, BeanDefinitionHolder definition, BeanDefinitionRegistry registry) {
ScopedProxyMode scopedProxyMode = metadata.getScopedProxyMode();
if (scopedProxyMode.equals(ScopedProxyMode.NO)) {
return definition;
}
boolean proxyTargetClass = scopedProxyMode.equals(ScopedProxyMode.TARGET_CLASS);
return ScopedProxyCreator.createScopedProxy(definition, registry, proxyTargetClass);
}
}
如果代理模式为ScopedProxyMode.NO,则不做任何处理,否则进行ScopedProxyCreator#createScopedProxy方法返回一个新的BeanDefinitionHolder对象
获取ScopedProxyFactoryBean类的BeanDefinitionHolder
final class ScopedProxyCreator {
public static BeanDefinitionHolder createScopedProxy(
BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry, boolean proxyTargetClass) {
return ScopedProxyUtils.createScopedProxy(definitionHolder, registry, proxyTargetClass);
}
}
public abstract class ScopedProxyUtils {
/**
* Generate a scoped proxy for the supplied target bean, registering the target
* bean with an internal name and setting 'targetBeanName' on the scoped proxy.
* @param definition the original bean definition
* @param registry the bean definition registry
* @param proxyTargetClass whether to create a target class proxy
* @return the scoped proxy definition
*
* 为提供的目标bean生成作用域代理,用内部名称注册目标bean,并在作用域代理上设置“target bean name”。
*/
public static BeanDefinitionHolder createScopedProxy(BeanDefinitionHolder definition,
BeanDefinitionRegistry registry, boolean proxyTargetClass) {
String originalBeanName = definition.getBeanName();
BeanDefinition targetDefinition = definition.getBeanDefinition();
//targetBeanName = "scopedTarget."+ originalBeanName
String targetBeanName = getTargetBeanName(originalBeanName);
// Create a scoped proxy definition for the original bean name,
// "hiding" the target bean in an internal target definition.
// 为原始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);
// ScopedProxyFactoryBean's "proxyTargetClass" default is TRUE, so we don't need to set it explicitly here.
// ScopedProxyFactoryBean的“proxyTargetClass”默认值为TRUE,因此不需要在这里显式设置它。
}
else {
proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
}
// Copy autowire settings from original bean definition.
// 从原始bean定义复制autowire设置。
proxyDefinition.setAutowireCandidate(targetDefinition.isAutowireCandidate());
proxyDefinition.setPrimary(targetDefinition.isPrimary());
if (targetDefinition instanceof AbstractBeanDefinition) {
proxyDefinition.copyQualifiersFrom((AbstractBeanDefinition) targetDefinition);
}
// The target bean should be ignored in favor of the scoped proxy.
// 为了支持作用域代理,应该忽略目标bean。
targetDefinition.setAutowireCandidate(false);
targetDefinition.setPrimary(false);
// Register the target bean as separate bean in the factory.
// 在工厂中将目标bean注册为单独的bean。
registry.registerBeanDefinition(targetBeanName, targetDefinition);
// Return the scoped proxy definition as primary bean definition
// (potentially an inner bean).
return new BeanDefinitionHolder(proxyDefinition, originalBeanName, definition.getAliases());
}
}
在上述过程中,主要做了三件事
- 新建一个ScopedProxyFactoryBean类的BeanDefinition,用于生成代理原来的Bean的代理Bean,设置所需的参数,确定代理类使用jdk代理还是CGLIB代理。
- 处理原来的BeanDefinition
- 原来的BeanDefinition中autowireCandidate属性和primary属性设置为false
- 将原来的BeanDefinition的以("scopedTarget."+原BeanName)作为新名称注册到容器中
- 返回包含原BeanName和ScopedProxyFactoryBean类的BeanDefinition信息的BeanDefinitionHolder。
- 以后再调用原来的beanName去获取bean的时候,获取的将是在ScopedProxyFactoryBean对象中获取的BeanDefinition的代理对象。
总结
在注册组件类的时候主要做了以下事情:
- 分析组件类生成BeanDefinition对象,将以下注解的配置元信息设置到BeanDefinition对象
- @Scope
- @Lazy
- @Primary
- @DependsOn
- @Role
- @Description
- 确定BeanName
- 根据@Scope的proxyMode属性,进行不同的作用域代理策略
- 将组件类的BeanDefinition或ScopedProxyFactoryBean类的BeanDefinition注册到容器中
网友评论