官术网_书友最值得收藏!

2.2.1 Bean的注冊(cè)

在使用Spring時(shí),我們可以通過(guò)獲取一個(gè)應(yīng)用上下文(ApplicationContext)對(duì)象來(lái)操作各種Bean,示例代碼如代碼清單2-9所示,相信你對(duì)這段代碼不會(huì)陌生。

代碼清單2-9 獲取應(yīng)用上下文對(duì)象的示例代碼

AnnotationConfigApplicationContext applicationContext
    = new AnnotationConfigApplicationContext(AppConfig.class);

這里的ApplicationContext接口代表的就是一個(gè)Spring IoC容器,而在Spring中存在一大批ApplicationContext接口的實(shí)現(xiàn)類。如果使用基于注解的配置方式,就可以使用上述代碼中的AnnotationConfigApplicationContext來(lái)初始化容器上下文對(duì)象。

在剛開(kāi)始閱讀Spring源碼時(shí),我建議你直接從AnnotationConfigApplicationContext的啟動(dòng)流程切入,這一流程位于它的構(gòu)造函數(shù)中,如代碼清單2-10所示。

代碼清單2-10 AnnotationConfigApplicationContext構(gòu)造函數(shù)代碼

public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
    this();
    //根據(jù)注解配置類注冊(cè)Bean
    register(annotatedClasses);
    //刷新容器
    refresh();
}

public AnnotationConfigApplicationContext(String... basePackages) {
    this();
    //根據(jù)包路徑配置掃描Bean
    scan(basePackages);
    //刷新容器
    refresh();
}

這兩個(gè)構(gòu)造函數(shù)的作用很明確,一個(gè)是根據(jù)注解配置類注冊(cè)Bean,另一個(gè)則是根據(jù)包路徑配置掃描Bean。這里我們以register()方法為例,來(lái)討論Bean的注冊(cè)過(guò)程,該方法如代碼清單2-11所示。

代碼清單2-11 AnnotationConfigApplicationContext的register()方法代碼

public void register(Class<?>... annotatedClasses) {
    Assert.notEmpty(annotatedClasses, "At least one annotated class must be specified");
    this.reader.register(annotatedClasses);
}

這里依賴AnnotatedBeanDefinitionReader工具類來(lái)完成Bean的注冊(cè)。AnnotatedBean-DefinitionReader會(huì)遍歷所有傳入的annotatedClasses注解類,然后通過(guò)代碼清單2-12所示的doRegisterBean()方法完成注冊(cè)。(由于該方法的代碼較長(zhǎng),我們對(duì)重要邏輯添加了注釋,對(duì)不重要的代碼做了省略。)

代碼清單2-12 AnnotationConfigApplicationContext的doRegisterBean()方法代碼

<T> void doRegisterBean(...) {
    //將注解配置類信息轉(zhuǎn)換成一種BeanDefinition
    AnnotatedGenericBeanDefinition abd = new
    AnnotatedGenericBeanDefinition(annotatedClass);
    …
    //獲取Bean的作用域元數(shù)據(jù),解析Bean作用域
    ScopeMetadata scopeMetadata =
    this.scopeMetadataResolver.resolveScopeMetadata(abd);

    //將Bean的作用域?qū)懟谺eanDefinition
    abd.setScope(scopeMetadata.getScopeName());

    //生成beanName
    String beanName = (name != null ? name :
    this.beanNameGenerator.generateBeanName(abd, this.registry));

    //解析AnnotatedBeanDefinitionReader中的@Lazy、@Primary等注解
    AnnotationConfigUtils.processCommonDefinitionAnnotations(abd);

    //處理@Qualifier注解
    if (qualifiers != null) {
        for (Class<? extends Annotation> qualifier : qualifiers) {
            if (Primary.class == qualifier) {
                // 如果設(shè)置了@Primary注解,則設(shè)置當(dāng)前Bean為首選Bean
                abd.setPrimary(true);
            }
            else if (Lazy.class == qualifier) {
                //如果設(shè)置了@Lazy注解,則設(shè)置當(dāng)前Bean為延遲加載模式
                abd.setLazyInit(true);
            }
            else {
                //其他注解,則添加到BeanDefinition中
                abd.addQualifier(new AutowireCandidateQualifier(qualifier));
            }
        }
    }
    …
    //注冊(cè)Bean對(duì)象
    BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);
}

這段代碼包含Bean注冊(cè)過(guò)程中的三個(gè)核心步驟,如圖2-1所示。

043-1

圖2-1 AnnotatedBeanDefinitionReader中Bean注冊(cè)的核心步驟示意圖

首先,我們構(gòu)建用來(lái)描述Bean實(shí)例信息的BeanDefinition對(duì)象,這需要將注解配置類信息轉(zhuǎn)成AnnotatedGenericBeanDefinition數(shù)據(jù)結(jié)構(gòu),而AnnotatedGenericBeanDefinition就是一種BeanDefinition,包含了Bean的構(gòu)造函數(shù)參數(shù)、各種屬性值以及所添加的注解信息。

然后,我們?cè)O(shè)置BeanDefinition屬性,這一步驟完成了對(duì)@Scope、@Primary、@Lazy等注解的處理。

最后,通過(guò)registerBeanDefinition()方法完成Bean的注冊(cè),該方法內(nèi)部通過(guò)Listable-BeanFactory的實(shí)現(xiàn)類DefaultListableBeanFactory將Bean定義信息注冊(cè)到Spring IoC容器中。ListableBeanFactory是Spring中常用的一個(gè)BeanFactory,通過(guò)這個(gè)接口,我們可以一次獲取多個(gè)Bean。

主站蜘蛛池模板: 腾冲县| 同仁县| 长岛县| 寻乌县| 兴仁县| 翼城县| 嵩明县| 津南区| 嘉定区| 巴中市| 松潘县| 紫金县| 琼海市| 格尔木市| 鄂伦春自治旗| 和林格尔县| 温泉县| 元江| 三都| 龙里县| 清水县| 石渠县| 平潭县| 曲靖市| 邹城市| 温泉县| 庆云县| 宝兴县| 右玉县| 拉萨市| 华容县| 闻喜县| 夏津县| 大竹县| 左云县| 宁明县| 甘谷县| 迁西县| 吴忠市| 尤溪县| 谷城县|