[Spring]RootBeanDefinition禾酱、GenericBeanDefinition、ChildBeanDefinition

BeanDefinition

從我的上一篇文章你可以知道滓走,BeanDefinition定義了一個Bean大概需要什么信息,給這些信息定義了一些getter和setter方法腰懂,作為接口層它不負(fù)責(zé)定義具體的參數(shù),AbstractBeanDefinition對這個接口進(jìn)行了實現(xiàn),它提供了一個BeanDefinition所需要具備的基本能力,如果需要擴(kuò)展功能哗蜈,那么可以對這個類進(jìn)行繼承,再添磚加瓦即可。今天我們來看看AbstractBeanDefinition的三個子類:

  • RootBeanDefinition
  • ChildBeanDefinition
  • GenericBeanDefinition

RootBeanDefinition

從Spring2.5開始,RootBeanDefinition僅作為運行時的BeanDefinition視圖洞翩。如果需要編程定義BeanDefinition稽犁,那么推薦使用GenericBeanDefinition。
Spring的解釋是:GenericBeanDefinition的優(yōu)勢在于骚亿,它允許動態(tài)定義父依賴項已亥,而不是一個以"硬編碼"定義BeanDefinition的角色。
也就是說来屠,bean的一般形式是以GenericBeanDefinition的標(biāo)準(zhǔn)形式存在的陷猫,在特定的時機(jī),會將GenericBeanDefinition轉(zhuǎn)成RootBeanDefinition

RootBeanDefinition特點

  • 存儲BeanDefinitionHolder對象星虹,該對象用來存儲Bean的name與alias的對應(yīng)關(guān)系,提供BeanDefinition的訪問方式
  • AnnotatedElement,這個是Java反射包的注解溶诞,開發(fā)者可以通過它來操作注解讯蒲。如平時常見到的getAnnotation()getAnnotations()弃榨、isAnnotationPresent()
  • allowCaching,是否允許緩存
  • isFactoryMethodUnique,工廠方法是否唯一
  • targetType,與Java泛型相關(guān)的工具類
  • resolvedTargetType,當(dāng)前類持有的Class對象
  • factoryMethodToIntrospect,緩存工廠方法
  • Executable,緩存已經(jīng)解析的構(gòu)造函數(shù)或者方法晴股,Executable是Method和Construct的父類
  • constructorArgumentsResolved,布爾值瞬雹,表示構(gòu)造函數(shù)是否被解析完畢
  • resolvedConstructorArguments,緩存被完全解析的構(gòu)造函數(shù)參數(shù)
  • postProcessed,是否被MergedBeanDefinitionPostProcessor處理
  • beforeInstantiationResolved,已啟動實例化前的后處理器
  • externallyManagedInitMethods,初始化時的回調(diào)函數(shù)
  • externallyManagedDestroyMethods,銷毀時的回調(diào)函數(shù)
  • constructorArgumentLockpostProcessingLock,對象鎖,有興趣的可以自行深入唬渗。這里不做闡述

此外减江,RootBeanDefinition不可以進(jìn)行setParentName()操作囚霸。
可以看到它存儲了許多關(guān)于注解與反射相關(guān)的信息,這或許會在某些時機(jī)用到這些信息進(jìn)行反射。

Demo

通過Java代碼來實例化一個RootBeanDefinition

Root
public class Root {

    private String name;

    private String description;

    private boolean isRoot;

    public Root() {

    }

    /**
     * 構(gòu)造函數(shù)
     * @param name 名稱 對應(yīng)的index為 0
     * @param description 描述 對應(yīng)的index為 1
     * @param isRoot 是否是父BeanDefinition 對應(yīng)的index為 2
     */
    public Root(String name, String description, Boolean isRoot) {
        this.name = name;
        this.description = description;
        this.isRoot = isRoot;
    }

    @Override
    public String toString() {
        return "Root{" +
                "name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", isRoot=" + isRoot +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public boolean getIsRoot() {
        return isRoot;
    }

    public void setIsRoot(boolean root) {
        isRoot = root;
    }
}
Child
package com.xjm.model;

/**
 * @author jaymin
 * 2020/11/29 14:21
 */
public class Child {
    private String name;

    private String description;

    private boolean isRoot;

    private String parentName;

    public Child(String name, String description, boolean isRoot, String parentName) {
        this.name = name;
        this.description = description;
        this.isRoot = isRoot;
        this.parentName = parentName;
    }

    public Child() {
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public boolean getIsRoot() {
        return isRoot;
    }

    public void setIsRoot(boolean root) {
        isRoot = root;
    }

    public String getParentName() {
        return parentName;
    }

    public void setParentName(String parentName) {
        this.parentName = parentName;
    }

    @Override
    public String toString() {
        return "Child{" +
                "name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", isRoot=" + isRoot +
                ", parentName='" + parentName + '\'' +
                '}';
    }
}

這里定義的對象待會會復(fù)用店归,我就不重新定義了

RootBeanDefinitionDemo
package com.xjm.bean.definition;

import com.xjm.model.Root;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author jaymin<br>
 * <p>
 * 2020/11/29 13:28
 */
@SuppressWarnings("all")
public class RootBeanDefinitionDemo {

    /**
     * 通過構(gòu)造器注入?yún)?shù)獲取RootBeanDefinition
     *
     * @return
     */
    public static RootBeanDefinition getRootBeanDefinitionByConstruct() {
        ConstructorArgumentValues cargs = new ConstructorArgumentValues();
        cargs.addIndexedArgumentValue(0, "rootA");
        cargs.addIndexedArgumentValue(1, "This is a RootBeanDefinition");
        cargs.addIndexedArgumentValue(2, true);
        RootBeanDefinition rootBeanDefinitionA = new RootBeanDefinition(Root.class, cargs, null);
        return rootBeanDefinitionA;
    }

    /**
     * 通過Setter的方式注入?yún)?shù),返回RootBeanDefinition
     *
     * @return
     */
    public static RootBeanDefinition getRootBeanDefinitionBySetter() {
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.addPropertyValue("name", "rootB");
        propertyValues.addPropertyValue("description", "This is a RootBeanDefinition");
        propertyValues.addPropertyValue("isRoot", true);
        RootBeanDefinition rootBeanDefinitionB = new RootBeanDefinition(Root.class, null, propertyValues);
        return rootBeanDefinitionB;
    }

    public static void main(String[] args) {
        // 1. 構(gòu)建一個空的容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 2.創(chuàng)建一個RootBeanDefinition
        RootBeanDefinition rootBeanDefinitionA = getRootBeanDefinitionByConstruct();
        RootBeanDefinition rootBeanDefinitionB = getRootBeanDefinitionBySetter();
        applicationContext.registerBeanDefinition("rootA", rootBeanDefinitionA);
        applicationContext.registerBeanDefinition("rootB", rootBeanDefinitionB);
        // 這里埋一個點盟步,直到這里才調(diào)用了Root對象的構(gòu)造函數(shù)
        applicationContext.refresh();
        Root rootA = ((Root) applicationContext.getBean("rootA"));
        Root rootB = ((Root) applicationContext.getBean("rootB"));
        System.out.println(rootA.toString());
        System.out.println(rootB.toString());
    }
}
root

ChildBeanDefinition

支持setParentName(),參數(shù)為父RootBeanDefinition的name,通過構(gòu)造函數(shù)的方式進(jìn)行設(shè)置繼承關(guān)系.Spring的注釋寫到多數(shù)情況下GenericBeanDefinition可以替代ChildBeanDefinition,所以這里就不詳細(xì)講了憋他,提供一個demo供大家品味.

ChildBeanDefinitionDemo

package com.xjm.bean.definition;

import com.xjm.model.Child;
import com.xjm.model.Root;
import org.springframework.beans.factory.support.ChildBeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author jaymin<br>
 * <p>
 * 2020/11/29 14:20
 */
@SuppressWarnings("all")
public class ChildBeanDefinitionDemo {

    public static void main(String[] args) {
        // 1. 構(gòu)建一個空的容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        String parentName = "rootB";
        String childName = "child";
        RootBeanDefinition rootBeanDefinition = RootBeanDefinitionDemo.getRootBeanDefinitionBySetter();
        ChildBeanDefinition childBeanDefinition = new ChildBeanDefinition(parentName);
        childBeanDefinition.setBeanClass(Child.class);
        childBeanDefinition.getPropertyValues().addPropertyValue("parentName", parentName);
        childBeanDefinition.getPropertyValues().addPropertyValue("isRoot", false);
        // 注冊
        applicationContext.registerBeanDefinition(parentName, rootBeanDefinition);
        applicationContext.registerBeanDefinition(childName, childBeanDefinition);
        // 刷新上下文
        applicationContext.refresh();
        Root root = applicationContext.getBean(Root.class);
        Child child = (Child) applicationContext.getBean(childName);
        System.out.println(root.toString());
        System.out.println(child.toString());
    }
}

GenericBeanDefinition

提供了setParentName()的方法,并且是setter的方式牲迫,通過讀Spring的注釋影晓,它如此描述道:

GenericBeanDefinition是一站式商店饵婆,用于標(biāo)準(zhǔn)bean定義。像任何bean定義一樣功偿,它允許指定一個類以及可選的構(gòu)造函數(shù)參數(shù)值和屬性值心傀。另外,可以通過“ parentName”屬性靈活地配置從父bean定義派生的內(nèi)容拆讯。


child

GenericBeanDefinitionDemo

package com.xjm.bean.definition;

import com.xjm.model.Child;
import com.xjm.model.Root;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
 * @author jaymin
 * 2020/11/29 14:57
 */
public class GenericBeanDefinitionDemo {

    public static GenericBeanDefinition getRootBeanDefinition() {
        GenericBeanDefinition rootBeanDefinition = new GenericBeanDefinition();
        rootBeanDefinition.setBeanClass(Root.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.add("name", "root")
                .add("description", "I am a rootBeanDefinition")
                .add("isRoot", true);
        rootBeanDefinition.setPropertyValues(propertyValues);
        return rootBeanDefinition;
    }

    public static GenericBeanDefinition getChildBeanDefinition() {
        GenericBeanDefinition childBeanDefinition = new GenericBeanDefinition();
        childBeanDefinition.setBeanClass(Child.class);
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.add("parentName", "root");
        childBeanDefinition.setParentName("root");
        childBeanDefinition.setPropertyValues(propertyValues);
        return childBeanDefinition;
    }

    public static void main(String[] args) {
        // 1. 構(gòu)建一個空的容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        GenericBeanDefinition rootBeanDefinition = getRootBeanDefinition();
        GenericBeanDefinition childBeanDefinition = getChildBeanDefinition();
        applicationContext.registerBeanDefinition("root", rootBeanDefinition);
        applicationContext.registerBeanDefinition("child", childBeanDefinition);
        applicationContext.refresh();
        Root root = applicationContext.getBean(Root.class);
        Child child = applicationContext.getBean(Child.class);
        System.out.println(root.toString());
        System.out.println(child.toString());
    }
}
GenericBeanDefinition

可以看到脂男,我們只用了一個GenericBeanDefinition就可以完成RootBeanDefinition和RootBeanDefinition能做到的事情。只需要setParentName()种呐,就可以拷貝另一個BeanDefinition的信息宰翅。易于擴(kuò)展

留給讀者的話

Spring源碼工程非常地龐大,但是提供了大量的注釋陕贮,有的時候光變量就一大堆堕油,我們怎么讓這些東西給我們留下一個深刻的印象呢,唯有實踐加上思考肮之。我個人知識儲量尚未足夠豐富掉缺,只能留下一些代碼,有興趣的朋友可以自行跟著實現(xiàn)一下戈擒,感受一下Spring的強(qiáng)大之處眶明。至于更深層的原理,目前尚未能完全講的透徹筐高。如有不對的地方搜囱,歡迎指正丑瞧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蜀肘,隨后出現(xiàn)的幾起案子绊汹,更是在濱河造成了極大的恐慌,老刑警劉巖扮宠,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件西乖,死亡現(xiàn)場離奇詭異,居然都是意外死亡坛增,警方通過查閱死者的電腦和手機(jī)获雕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來收捣,“玉大人届案,你說我怎么就攤上這事“瞻” “怎么了楣颠?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長昆婿。 經(jīng)常有香客問我球碉,道長蜓斧,這世上最難降的妖魔是什么仓蛆? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮挎春,結(jié)果婚禮上看疙,老公的妹妹穿的比我還像新娘。我一直安慰自己直奋,他們只是感情好能庆,可當(dāng)我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著脚线,像睡著了一般搁胆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上邮绿,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天渠旁,我揣著相機(jī)與錄音,去河邊找鬼船逮。 笑死顾腊,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挖胃。 我是一名探鬼主播杂靶,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼梆惯,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吗垮?” 一聲冷哼從身側(cè)響起垛吗,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烁登,沒想到半個月后职烧,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡防泵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年蚀之,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片捷泞。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡足删,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锁右,到底是詐尸還是另有隱情失受,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布咏瑟,位于F島的核電站拂到,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏码泞。R本人自食惡果不足惜兄旬,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望余寥。 院中可真熱鬧领铐,春花似錦、人聲如沸宋舷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽祝蝠。三九已至音诈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間绎狭,已是汗流浹背细溅。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留坟岔,地道東北人谒兄。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像社付,于是被迫代替她去往敵國和親承疲。 傳聞我的和親對象是個殘疾皇子邻耕,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容