AnnotationConfigApplicationConte

2020-02-02  本文已影响0人  zekers

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 &mdash; 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

参数解析:

  1. beanClass:解析的目标类
  2. name:这里为空,注册的名字
  3. qualifiers:这里为空,暂不分析
  4. supplier:这里为空,暂不分析
  5. customizers:这里为空,暂不分析

步骤:

  1. 生成AnnotatedGenericBeanDefinition对象(存储Bean的描述信息的对象),持有beanClass,同时解析beanClass获取部分配置元数据(配置元数据即描述这个Bean的配置信息),存储到该BeanDefinition对象中;
  2. 暂时跳过;
  3. 这里无作用,略;
  4. 使用scopeMetadataResolver解析BeanDefinition上的@Scope标签,确定作用域元数据。然后设置到BeanDefinition上
  5. 解析BeanDefinition获得beanName(Bean的名称)
  6. 通过AnnotatedBeanDefinition上的配置元数据,解析存储在该配置元数据上的以下的注解信息,获取注解上的值,存储到该AnnotatedBeanDefinition对象上
    1. @Lazy
    2. @Primary
    3. @DependsOn
    4. @Role
    5. @Description
  7. 这里无作用,略;
  8. 这里无作用,略;
  9. 生成BeanDefinitionHolder对象,持有BeanDefinition和Bean的名称
  10. 作用域代理策略,将根据参数判断是否需要代理,使用jdk代理还是CGLIB代理
  11. 往容器中注册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;
    }
}

步骤:

  1. 新建ScopeMetadata对象
  2. 使用AnnotationConfigUtils工具类获取标记了@Scope的注解对象(AnnotationAttributes)
  3. 如果注解对象不为空,则解析注解对象的属性,并设置给配置ScopeMetadata(保存Scope注解信息的配置元数据)
    1. value—>setScopeName
    2. proxyMode—>设置setScopedProxyMode:作用域代理模式,用于决定是否要代理这个类,代理的模式是jdk代理还是CGLIB代理
  4. 返回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的策略:

  1. 如果definition是AnnotatedBeanDefinition,则会通过解析类上的注解,获取以下注解(包括继承的注解类)上value的值作为BeanName
    1. @Component
    2. @ManagedBean
    3. @Named
  2. 如果以上注解中value的值为null,将会获取类名,转化为beanName,转换方式如下
    1. 常规类:package.MyConfiguration—>myConfiguration
    2. 静态内部类: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());
    }
}

在上述过程中,主要做了三件事

  1. 新建一个ScopedProxyFactoryBean类的BeanDefinition,用于生成代理原来的Bean的代理Bean,设置所需的参数,确定代理类使用jdk代理还是CGLIB代理。
  2. 处理原来的BeanDefinition
    1. 原来的BeanDefinition中autowireCandidate属性和primary属性设置为false
    2. 将原来的BeanDefinition的以("scopedTarget."+原BeanName)作为新名称注册到容器中
  3. 返回包含原BeanName和ScopedProxyFactoryBean类的BeanDefinition信息的BeanDefinitionHolder。
    1. 以后再调用原来的beanName去获取bean的时候,获取的将是在ScopedProxyFactoryBean对象中获取的BeanDefinition的代理对象。

总结

在注册组件类的时候主要做了以下事情:

  1. 分析组件类生成BeanDefinition对象,将以下注解的配置元信息设置到BeanDefinition对象
    1. @Scope
    2. @Lazy
    3. @Primary
    4. @DependsOn
    5. @Role
    6. @Description
  2. 确定BeanName
  3. 根据@Scope的proxyMode属性,进行不同的作用域代理策略
  4. 将组件类的BeanDefinition或ScopedProxyFactoryBean类的BeanDefinition注册到容器中
上一篇下一篇

猜你喜欢

热点阅读