AnnotationConfigApplicationContext 源碼分析(二):注冊配置類

AnnotationConfigApplicationContext 源碼分析(二):注冊配置類

本文是作者的個人學(xué)習(xí)筆記,僅做參考,Spring代碼版本5.2.2

AnnotationConfigApplicationContext 源碼分析(一)

注冊配置類

注冊配置類將要解析由AnnotationConfigRegistry接口所提供的#register(Class<?>... componentClasses)方法,該方法用于注冊一個或多個組件類(標(biāo)注了@component的類),注意的是注冊完了之后容器必須調(diào)用#refresh()方法,不然將會導(dǎo)致未知的問題。

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>請注意,必須調(diào)用{@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);
    }
}

根據(jù)代碼可以知道,實際上調(diào)用的是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}的調(diào)用是等冪的;多次添加同一個組件類沒有額外的效果。
     * @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循環(huán)依次調(diào)用注冊組件類,這里就不過多解析

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,從類聲明的注釋中派生其元數(shù)據(jù)。
     * @param beanClass 注冊的Bean的Class對象
     * @param name  bean的顯式名稱
     * @param qualifiers 除了bean類級別的限定符之外,要考慮的特定限定符注釋(如果有的話)
     * @param supplier 用于創(chuàng)建bean實例的回調(diào)(可以是{@code null})
     * @param customizers 一個或多個回調(diào),用于自定義工廠的{@link BeanDefinition},例如設(shè)置lazy init或primary標(biāo)志
     * @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、根據(jù)beanClass生成AnnotatedGenericBeanDefinition
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
        //2、
        if (this.conditionEvaluator.shouldSkip(abd.getMetadata())) {
            return;
        }
    //3、supplier==null,略
        abd.setInstanceSupplier(supplier);
    //4、解析BeanDefinition上的@Scope標(biāo)簽,設(shè)置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上設(shè)置注解上設(shè)置的配置元數(shù)據(jù)
        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標(biāo)簽的proxyMode屬性
        definitionHolder = AnnotationConfigUtils.applyScopedProxyMode(scopeMetadata, definitionHolder, this.registry);
    //11、注冊definitionHolder到容器中
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
    }
}

往容器中注冊一個bean

參數(shù)解析:

  1. beanClass:解析的目標(biāo)類
  2. name:這里為空,注冊的名字
  3. qualifiers:這里為空,暫不分析
  4. supplier:這里為空,暫不分析
  5. customizers:這里為空,暫不分析

步驟:

  1. 生成AnnotatedGenericBeanDefinition對象(存儲Bean的描述信息的對象),持有beanClass,同時解析beanClass獲取部分配置元數(shù)據(jù)(配置元數(shù)據(jù)即描述這個Bean的配置信息),存儲到該BeanDefinition對象中;
  2. 暫時跳過;
  3. 這里無作用,略;
  4. 使用scopeMetadataResolver解析BeanDefinition上的@Scope標(biāo)簽,確定作用域元數(shù)據(jù)。然后設(shè)置到BeanDefinition上
  5. 解析BeanDefinition獲得beanName(Bean的名稱)
  6. 通過AnnotatedBeanDefinition上的配置元數(shù)據(jù),解析存儲在該配置元數(shù)據(jù)上的以下的注解信息,獲取注解上的值,存儲到該AnnotatedBeanDefinition對象上
    1. @Lazy
    2. @Primary
    3. @DependsOn
    4. @Role
    5. @Description
  7. 這里無作用,略;
  8. 這里無作用,略;
  9. 生成BeanDefinitionHolder對象,持有BeanDefinition和Bean的名稱
  10. 作用域代理策略,將根據(jù)參數(shù)判斷是否需要代理,使用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類創(chuàng)建一個新的AnnotatedGenericBeanDefinition。
     * @param beanClass 加載的bean類
     */
    public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
        setBeanClass(beanClass);
        this.metadata = AnnotationMetadata.introspect(beanClass);
    }
}

這個類是GenericBeanDefinition(GenericBeanDefinition是通用的BeanDefinition)的基礎(chǔ)上實現(xiàn)AnnotatedBeanDefinition接口,該接口提供了用于暴露注解相關(guān)的配置元數(shù)據(jù),即AnnotationMetadata的接口。

AnnotatedGenericBeanDefinition類型的BeanDefinition通常只在注冊組件類的時候被定義。

步驟:

1. BeanDefinition持有類對象
2. 通過內(nèi)?。╦ava機(jī)制)類對象生成StandardAnnotationMetadata對象(配置元數(shù)據(jù)對象)并被當(dāng)前BeanDefinition持有。相關(guān)類將另起文章分析

解析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)}.
 * 默認(rèn)情況下檢查bean類上是否存在Spring的{@link Scope@Scope}注釋的{@link ScopeMetadataResolver}實現(xiàn)。
 * <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工具類獲取標(biāo)記了@Scope的注解對象(AnnotationAttributes)
  3. 如果注解對象不為空,則解析注解對象的屬性,并設(shè)置給配置ScopeMetadata(保存Scope注解信息的配置元數(shù)據(jù))
    1. value—>setScopeName
    2. proxyMode—>設(shè)置setScopedProxyMode:作用域代理模式,用于決定是否要代理這個類,代理的模式是jdk代理還是CGLIB代理
  4. 返回ScopeMetadata對象后,通過BeanDefinition#setScope(String scopeName)設(shè)置到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,將會獲取類名,轉(zhuǎn)化為beanName,轉(zhuǎn)換方式如下
    1. 常規(guī)類:package.MyConfiguration—>myConfiguration
    2. 靜態(tài)內(nèi)部類: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,則不做任何處理,否則進(jìn)行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
     *
     * 為提供的目標(biāo)bean生成作用域代理,用內(nèi)部名稱注冊目標(biāo)bean,并在作用域代理上設(shè)置“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名稱創(chuàng)建一個作用域代理定義,
        // 在內(nèi)部目標(biāo)定義中“隱藏”目標(biāo)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”默認(rèn)值為TRUE,因此不需要在這里顯式設(shè)置它。
        }
        else {
            proxyDefinition.getPropertyValues().add("proxyTargetClass", Boolean.FALSE);
        }

        // Copy autowire settings from original bean definition.
        // 從原始bean定義復(fù)制autowire設(shè)置。
        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.
        // 為了支持作用域代理,應(yīng)該忽略目標(biāo)bean。
        targetDefinition.setAutowireCandidate(false);
        targetDefinition.setPrimary(false);

        // Register the target bean as separate bean in the factory.
        // 在工廠中將目標(biāo)bean注冊為單獨(dú)的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,設(shè)置所需的參數(shù),確定代理類使用jdk代理還是CGLIB代理。
  2. 處理原來的BeanDefinition
    1. 原來的BeanDefinition中autowireCandidate屬性和primary屬性設(shè)置為false
    2. 將原來的BeanDefinition的以("scopedTarget."+原BeanName)作為新名稱注冊到容器中
  3. 返回包含原BeanName和ScopedProxyFactoryBean類的BeanDefinition信息的BeanDefinitionHolder。
    1. 以后再調(diào)用原來的beanName去獲取bean的時候,獲取的將是在ScopedProxyFactoryBean對象中獲取的BeanDefinition的代理對象。

總結(jié)

在注冊組件類的時候主要做了以下事情:

  1. 分析組件類生成BeanDefinition對象,將以下注解的配置元信息設(shè)置到BeanDefinition對象
    1. @Scope
    2. @Lazy
    3. @Primary
    4. @DependsOn
    5. @Role
    6. @Description
  2. 確定BeanName
  3. 根據(jù)@Scope的proxyMode屬性,進(jìn)行不同的作用域代理策略
  4. 將組件類的BeanDefinition或ScopedProxyFactoryBean類的BeanDefinition注冊到容器中
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容