逐行閱讀Spring5.X源碼(三) BeanDefinition的實現(xiàn)類詳解,拔高

溫馨提示:如果您是剛接觸spring源碼不久,建議您先閱讀BeanDefinitino的前兩篇博文才能更好的理解本篇博文
? ? ? ?書接上回。

image.png

? ? ? ?上回咱們講了BeanDefinition的父接口及父接口實現(xiàn)類。本篇博文咱么繼續(xù)講BeanDefinition的實現(xiàn)類。包括AbstractBeanDefinition、RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition、AnnotateGenericBeanDefinition、ScannerGenericBeanDefinition。

1. AbstractBeanDefinition

? ? ? ?AbstractBeanDefinition是抽象類,它是眾多子類的父類。前兩篇文章講的BeanDefinition屬性值大都保存在AbstractBeanDefinition,并實現(xiàn)了子BeanDefinition通用方法。同時它也繼承了BeanMetadataAttributeAccessor完成attribute和source的操作。我們看一下它的關(guān)鍵源碼:

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
        implements BeanDefinition, Cloneable {
        
    // 此處省略靜態(tài)變量以及final變量
    
    @Nullable
    private volatile Object beanClass;
    /**
     * bean的作用范圍,對應(yīng)bean屬性scope
     */
    @Nullable
    private String scope = SCOPE_DEFAULT;
    /**
     * 是否是抽象,對應(yīng)bean屬性abstract
     */
    private boolean abstractFlag = false;
    /**
     * 是否延遲加載,對應(yīng)bean屬性lazy-init
     */
    private boolean lazyInit = false;
    /**
     * 自動注入模式,對應(yīng)bean屬性autowire
     */
    private int autowireMode = AUTOWIRE_NO;
    /**
     * 依賴檢查,Spring 3.0后棄用這個屬性
     */
    private int dependencyCheck = DEPENDENCY_CHECK_NONE;
    /**
     * 用來表示一個bean的實例化依靠另一個bean先實例化,對應(yīng)bean屬性depend-on
     */
    @Nullable
    private String[] dependsOn;
    /**
     * autowire-candidate屬性設(shè)置為false,這樣容器在查找自動裝配對象時,
     * 將不考慮該bean,即它不會被考慮作為其他bean自動裝配的候選者,
     * 但是該bean本身還是可以使用自動裝配來注入其他bean的
     */
    private boolean autowireCandidate = true;
    /**
     * 自動裝配時出現(xiàn)多個bean候選者時,將作為首選者,對應(yīng)bean屬性primary
     */
    private boolean primary = false;
    /**
     * 用于記錄Qualifier,對應(yīng)子元素qualifier
     */
    private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);

    @Nullable
    private Supplier<?> instanceSupplier;
    /**
     * 允許訪問非公開的構(gòu)造器和方法,程序設(shè)置
     */
    private boolean nonPublicAccessAllowed = true;
    /**
     * 是否以一種寬松的模式解析構(gòu)造函數(shù),默認為true,
     * 如果為false,則在以下情況
     * interface ITest{}
     * class ITestImpl implements ITest{};
     * class Main {
     *     Main(ITest i) {}
     *     Main(ITestImpl i) {}
     * }
     * 拋出異常,因為Spring無法準(zhǔn)確定位哪個構(gòu)造函數(shù)程序設(shè)置
     */
    private boolean lenientConstructorResolution = true;
    /**
     * 對應(yīng)bean屬性factory-bean,用法:
     * <bean id = "instanceFactoryBean" class = "example.chapter3.InstanceFactoryBean" />
     * <bean id = "currentTime" factory-bean = "instanceFactoryBean" factory-method = "createTime" />
     */
    @Nullable
    private String factoryBeanName;
    /**
     * 對應(yīng)bean屬性factory-method
     */
    @Nullable
    private String factoryMethodName;
    /**
     * 記錄構(gòu)造函數(shù)注入屬性,對應(yīng)bean屬性constructor-arg
     */
    @Nullable
    private ConstructorArgumentValues constructorArgumentValues;
    /**
     * 普通屬性集合,就是存放你業(yè)務(wù)類的屬性的地方
     */
    @Nullable
    private MutablePropertyValues propertyValues;
    /**
     * 方法重寫的持有者,記錄lookup-method、replaced-method元素
     */
    @Nullable
    private MethodOverrides methodOverrides;
    /**
     * 初始化方法,對應(yīng)bean屬性init-method
     */
    @Nullable
    private String initMethodName;
    /**
     * 銷毀方法,對應(yīng)bean屬性destroy-method
     */
    @Nullable
    private String destroyMethodName;
    /**
     * 是否執(zhí)行init-method,程序設(shè)置
     */
    private boolean enforceInitMethod = true;
    /**
     * 是否執(zhí)行destroy-method,程序設(shè)置
     */
    private boolean enforceDestroyMethod = true;
    /**
     * 是否是用戶定義的而不是應(yīng)用程序本身定義的,創(chuàng)建AOP時候為true,程序設(shè)置
     */
    private boolean synthetic = false;
    /**
     * 定義這個bean的應(yīng)用,APPLICATION:用戶,INFRASTRUCTURE:完全內(nèi)部使用,與用戶無關(guān),
     * SUPPORT:某些復(fù)雜配置的一部分
     * 程序設(shè)置
     */
    private int role = BeanDefinition.ROLE_APPLICATION;
    /**
     * bean的描述信息
     */
    @Nullable
    private String description;
    /**
     * 這個bean定義的資源
     */
    @Nullable
    private Resource resource;
}

? ? ? ?操作方法我就不列出來了,主要就是對屬性的設(shè)置和獲取,類似于getter和setter方法,讀者自行閱讀。總之,AbstractBeanDefinition 就是保存了屬性值并對屬性值進行設(shè)置和讀取。記住這一點就行了。當(dāng)然,有的讀者說,源碼很簡單,但是里面的屬性值具體代表啥意思呢?在什么時候用到呢?前兩篇博文我說了,我講解BeanDefinition這塊內(nèi)容就是讓大家純粹的理解BeanDefition的作用,BeanDefition是整個spring源碼中的基礎(chǔ)。在以后的學(xué)習(xí)中,BeanDefinition中的屬性值作用會慢慢的浮出水面,大家不要著急。
? ? ? ?AbstractBeanDefinition 其實已經(jīng)涵蓋了所有屬性了,spring為什么要提供這么多的子類?正所謂,既生瑜何生亮!筆者認為,完全可以用一個AbstractBeanDefinition 代替所有的子類,只不過spring為了模塊化,不同的BeanDefinition可能從代碼角度來講都一樣,但是從設(shè)計角度來講我們要模塊化,要拆分,不通模塊的BeanDefinition無論從設(shè)計還是功能肯定有差異,我們當(dāng)然可以將這些差異規(guī)避在AbstractBeanDefinition ,但是這不利于維護和擴展,更不利于閱讀理解。
我們看一下ChildBeanDefinition源碼中的類注解:

 * <p><b>NOTE:</b> Since Spring 2.5, the preferred way to register bean
 * definitions programmatically is the {@link GenericBeanDefinition} class,
 * which allows to dynamically define parent dependencies through the
 * {@link GenericBeanDefinition#setParentName} method. This effectively
 * supersedes the ChildBeanDefinition class for most use cases.

百度翻一下:


image.png

? ? ? ?意思就是說,spring2.5以后GenericBeanDefinition是首選的,也就是說spring2.5以前的版本根本就沒有GenericBeanDefinition這個類。spring總得向前發(fā)展啊,更重要的是盡可能的保持向下兼容呀!其實,RootBeanDefinition也有這種類似的注解,你不信你去看源碼!現(xiàn)如今,我們已經(jīng)不使用ChildBeanDefinition了,完全北GenericBeanDefinition給替代了,但是還在使用RootBeanDefinition。

? ? ? ?Root,Child根據(jù)字面意思,好像是父子關(guān)系,AbstractBeanDefinition 中有個屬性叫abstract(是否是抽象類),抽象類無法實例化呀,不能保存到beanDefinitionMap容器中??!有存在的意義嗎?
? ? ? ?有,模板!如果一個BeanDefinition中的屬性abstract為true,它是讓spring來繼承它,而不是實例化它。
? ? ? ?舉個例子吧:

//業(yè)務(wù)類
public class InterService {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);

        //模板BeanDefinition
        RootBeanDefinition root = new RootBeanDefinition();
        //設(shè)置為抽象類
        root.setAbstract(true);
        root.setDescription("我是一個模板");
        root.setBeanClass(InterService.class);
        root.getPropertyValues().add("name","源碼之路");
        //注冊,放到IOC容器中
        context.registerBeanDefinition("interService",root);

        //child繼承root
        ChildBeanDefinition child = new ChildBeanDefinition("interService");
        //注冊,放到IOC容器中
        context.registerBeanDefinition("child",child);
        context.refresh();
    System.out.println(((InterService)context.getBean("child")).getName());

    }
}

打印結(jié)果:


image.p

? ? ? ?這里講一下這行代碼:

        root.getPropertyValues().add("name","源碼之路");

? ? ? ?上文AbstractBeanDefinition 源碼中有一個MutablePropertyValues類型的屬性叫propertyValues,我在注釋中是這么寫的:

        /**
     * 普通屬性集合,就是存放你業(yè)務(wù)類的屬性的地方
     */
        @Nullable
    private MutablePropertyValues propertyValues;

? ? ? ?什么意思呢?propertyValues只能保存你業(yè)務(wù)類的屬性,比如業(yè)務(wù)類InterService中有個name屬性, root.getPropertyValues().add("name","源碼之路");在后期spring實例化過程中,會將propertyValues中的屬性值一一對應(yīng)的賦值給業(yè)務(wù)對象。等同于xml文件中的配置:

    <bean  id="index" class="com.InterService" >
            <property name="name" value="源碼之路"></property>
        </bean>

? ? ? ?如果,我設(shè)置了一個業(yè)務(wù)類中不存在的屬性,就會報錯,比如:


image.png
image.png

? ? ? ?我說過,AbstractBeanDefinition中的屬性以后都會講到,別急,這個propertyValues只到啥意思了吧?
? ? ? ?繼續(xù),再添加一個業(yè)務(wù)類:

public class User {
    private String name;
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);

        //模板BeanDefinition
        RootBeanDefinition root = new RootBeanDefinition();
        //設(shè)置為抽象類
        root.setAbstract(true);
        root.setDescription("我是一個模板");
        root.setBeanClass(InterService.class);
        root.getPropertyValues().add("name","源碼之路");
        //注冊,放到IOC容器中
        context.registerBeanDefinition("interService",root);
        //child繼承root
        ChildBeanDefinition child = new ChildBeanDefinition("interService");
        child.setBeanClass(User.class);
        //注冊,放到IOC容器中
        context.registerBeanDefinition("child",child);
        context.refresh();
        System.out.println(((User)context.getBean("child")).getName());

    }
}

? ? ? ?我們只是增加了child.setBeanClass(User.class);這行代碼
? ? ? ?打印結(jié)果:


image.png

? ? ? ?也就是說User類相當(dāng)于繼承了InterService類,等同于xml文件:

        <bean  id="index" class="com.InterService" >
            <property name="name" value="源碼之路"></property>
        </bean>
        <bean  id="user" class="com.User" parent="index">
        </bean>

這里很繞,筆者當(dāng)時為了弄懂這里也是費了好大的勁。多讀兩遍就理解了。

2. GenericBeanDefinition

上文我們說GenericBeanDefinition可以替代RootBeanDefinition和ChildBeanDefinition,我們測試一下:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        //模板BeanDefinition
        GenericBeanDefinition root = new GenericBeanDefinition();
        //設(shè)置為抽象類
        root.setAbstract(true);
        root.setDescription("我是一個模板");
        root.setBeanClass(InterService.class);
        root.getPropertyValues().add("name","源碼之路");
        root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        //注冊,放到IOC容器中
        context.registerBeanDefinition("interService",root);

        //child繼承root
        GenericBeanDefinition child = new GenericBeanDefinition();
        child.setParentName("interService");
        child.setAbstract(false);
        child.setBeanClass(User.class);
        //注冊,放到IOC容器中
        context.registerBeanDefinition("child",child);

        context.refresh();

        System.out.println(((User)context.getBean("child")).getName());
        System.out.println(context.getBeanDefinition("child").getScope());

    }
}

? ? ? ?打印結(jié)果:


image.png

? ? ? ?我們閱讀下GenericBeanDefinition源碼:

public class GenericBeanDefinition extends AbstractBeanDefinition {

    //父BeanDefinition名字
    @Nullable
    private String parentName;


    /**
     * Create a new GenericBeanDefinition, to be configured through its bean
     * properties and configuration methods.
     * @see #setBeanClass
     * @see #setScope
     * @see #setConstructorArgumentValues
     * @see #setPropertyValues
     * 構(gòu)造方法,所有屬性均為空
     */
    public GenericBeanDefinition() {
        super();
    }

    /**
     * Create a new GenericBeanDefinition as deep copy of the given
     * bean definition.
     * @param original the original bean definition to copy from
     *  從一個給定的BeanDefinition中將屬性值copy給新的GenericBeanDefinition
     */
    public GenericBeanDefinition(BeanDefinition original) {
        super(original);
    }


    //設(shè)置父類名稱
    @Override
    public void setParentName(@Nullable String parentName) {
        this.parentName = parentName;
    }
    //獲取父類名稱
    @Override
    @Nullable
    public String getParentName() {
        return this.parentName;
    }

    //根據(jù)當(dāng)前GenericBeanDefinition克隆一個新的GenericBeanDefinition
    @Override
    public AbstractBeanDefinition cloneBeanDefinition() {
        return new GenericBeanDefinition(this);
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof GenericBeanDefinition)) {
            return false;
        }
        GenericBeanDefinition that = (GenericBeanDefinition) other;
        return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("Generic bean");
        if (this.parentName != null) {
            sb.append(" with parent '").append(this.parentName).append("'");
        }
        sb.append(": ").append(super.toString());
        return sb.toString();
    }

}

3. RootBeanDefinition

? ? ? ?但是,RootBeanDefinition卻不可以替換ChildBeanDefinition

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);

        //模板BeanDefinition
        RootBeanDefinition root = new RootBeanDefinition();
        //設(shè)置為抽象類
        root.setAbstract(true);
        root.setDescription("我是一個模板");
        root.setBeanClass(InterService.class);
        root.getPropertyValues().add("name","源碼之路");
        root.setScope(BeanDefinition.SCOPE_PROTOTYPE);
        //注冊,放到IOC容器中
        context.registerBeanDefinition("interService",root);

        //child繼承root
        RootBeanDefinition child = new RootBeanDefinition();
        child.setParentName("interService");
        child.setBeanClass(User.class);
        //注冊,放到IOC容器中
        context.registerBeanDefinition("child",child);

        context.refresh();

        System.out.println(((User)context.getBean("child")).getName());
        System.out.println(context.getBeanDefinition("child").getScope());

    }
}

image.png

? ? ? ?為什么?我們看child.setParentName("interService")這行代碼的源碼:

    @Override
    public void setParentName(@Nullable String parentName) {
        if (parentName != null) {
            throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
        }
    }

? ? ? ?看到了吧,你設(shè)置父類的時候spring給你拋異常,不允許。RootBeanDefinition的所有構(gòu)造函數(shù)也不給你提供一個設(shè)置父類的參數(shù)。那么問題來了,spring為什么這么做?筆者構(gòu)建好了spring源碼,然后筆者把RootBeanDefinition的源碼改了:
首先,在RootBeanDefinition增加一個parentName的屬性

@SuppressWarnings("serial")
public class RootBeanDefinition extends AbstractBeanDefinition {
      .....
    //父類名稱
    private String parentName;
       ....
{

其次,修改setParentName

    @Override
    public void setParentName(@Nullable String parentName) {
//      if (parentName != null) {
//          throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
//      }
        this.parentName = parentName;
    }

最后修改getParentName方法,注意,spring原來的就是return null;

    @Override
    public String getParentName() {
//      return null;
        return this.parentName;
    }

打印結(jié)果:


image.png

? ? ? ?此時,RootBeanDefinition充當(dāng)了ChildBeanDefinition的角色。留作業(yè),spring為什么這么做?不要告訴我setParentName拋異常所以不允許,我已經(jīng)證明該源碼可以了,我問的是spring源碼作者他當(dāng)時咋想的?我給你打個樣:這里涉及到bean合并。
? ? ? ?最后讀下RootBeanDefinition的源碼吧:

public class RootBeanDefinition extends AbstractBeanDefinition {
    
    //BeanDefinitionHolder存儲有Bean的名稱、別名、BeanDefinition
    @Nullable
    private BeanDefinitionHolder decoratedDefinition;
    // AnnotatedElement 是java反射包的接口,通過它可以查看Bean的注解信息
    @Nullable
    private AnnotatedElement qualifiedElement;
    //允許緩存
    boolean allowCaching = true;
    //從字面上理解:工廠方法是否唯一
    boolean isFactoryMethodUnique = false;
    //封裝了java.lang.reflect.Type,提供了泛型相關(guān)的操作,具體請查看:
    // ResolvableType 可以專題去了解一下子,雖然比較簡單 但常見
    @Nullable
    volatile ResolvableType targetType;
    //緩存class,表明RootBeanDefinition存儲哪個類的信息
    @Nullable
    volatile Class<?> resolvedTargetType;
    //緩存工廠方法的返回類型
    @Nullable
    volatile ResolvableType factoryMethodReturnType;

    /** Common lock for the four constructor fields below */
    final Object constructorArgumentLock = new Object();

    //緩存已經(jīng)解析的構(gòu)造函數(shù)或是工廠方法,Executable是Method、Constructor類型的父類
    @Nullable
    Executable resolvedConstructorOrFactoryMethod;
    //表明構(gòu)造函數(shù)參數(shù)是否解析完畢
    boolean constructorArgumentsResolved = false;
    //緩存完全解析的構(gòu)造函數(shù)參數(shù)
    @Nullable
    Object[] resolvedConstructorArguments;
    //緩存待解析的構(gòu)造函數(shù)參數(shù),即還沒有找到對應(yīng)的實例,可以理解為還沒有注入依賴的形參
    @Nullable
    Object[] preparedConstructorArguments;

    /** Common lock for the two post-processing fields below */
    final Object postProcessingLock = new Object();

    //表明是否被MergedBeanDefinitionPostProcessor處理過
    boolean postProcessed = false;
    //在生成代理的時候會使用,表明是否已經(jīng)生成代理
    @Nullable
    volatile Boolean beforeInstantiationResolved;

    //實際緩存的類型是Constructor、Field、Method類型
    @Nullable
    private Set<Member> externallyManagedConfigMembers;
    //InitializingBean中的init回調(diào)函數(shù)名——afterPropertiesSet會在這里記錄,以便進行生命周期回調(diào)
    @Nullable
    private Set<String> externallyManagedInitMethods;
    //DisposableBean的destroy回調(diào)函數(shù)名——destroy會在這里記錄,以便進行生命周期回調(diào)
    @Nullable
    private Set<String> externallyManagedDestroyMethods;

    //===========方法(只例舉部分)
    // 由此看出,RootBeanDefiniiton是木有父的
    @Override
    public String getParentName() {
        return null;
    }
    @Override
    public void setParentName(@Nullable String parentName) {
        if (parentName != null) {
            throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
        }
    }
    // 拿到class類型
    @Nullable
    public Class<?> getTargetType() {
        if (this.resolvedTargetType != null) {
            return this.resolvedTargetType;
        }
        ResolvableType targetType = this.targetType;
        return (targetType != null ? targetType.resolve() : null);
    }
    @Override
    public RootBeanDefinition cloneBeanDefinition() {
        return new RootBeanDefinition(this);
    }
}

? ? ? ?可以看到許多與反射相關(guān)的對象,這說明spring底層采用的是反射機制。
? ? ? ?總結(jié)一下,RootBeanDefiniiton保存了以下信息:
? ? ? ?1. 定義了id、別名與Bean的對應(yīng)關(guān)系(BeanDefinitionHolder)
? ? ? ?2. Bean的注解(AnnotatedElement)
? ? ? ?3. 具體的工廠方法(Class類型),包括工廠方法的返回類型,工廠方法的Method對象
? ? ? ?4. 構(gòu)造函數(shù)、構(gòu)造函數(shù)形參類型
? ? ? ?5. Bean的class對象
? ? ? ?可以看到,RootBeanDefinition與AbstractBeanDefinition是互補關(guān)系,RootBeanDefinition在AbstractBeanDefinition的基礎(chǔ)上定義了更多屬性,初始化Bean需要的信息基本完善

4. ChildBeanDefinition

? ? ? ?ChildBeanDefinition不能獨立存在,他必須繼承一個父類,為什么?我們看源碼:

public class ChildBeanDefinition extends AbstractBeanDefinition {

    //父類名稱
    @Nullable
    private String parentName;


    /**
     * Create a new ChildBeanDefinition for the given parent, to be
     * configured through its bean properties and configuration methods.
     * @param parentName the name of the parent bean
     * @see #setBeanClass
     * @see #setScope
     * @see #setConstructorArgumentValues
     * @see #setPropertyValues
     * 構(gòu)造函數(shù),必須設(shè)置一個父類
     */
    
    public ChildBeanDefinition(String parentName) {
        super();
        this.parentName = parentName;
    }

    /**
     * Create a new ChildBeanDefinition for the given parent.
     * @param parentName the name of the parent bean
     * @param pvs the additional property values of the child
     * 構(gòu)造函數(shù),設(shè)置父類和業(yè)務(wù)類屬性   
     */
    public ChildBeanDefinition(String parentName, MutablePropertyValues pvs) {
        super(null, pvs);
        this.parentName = parentName;
    }

    /**
     * Create a new ChildBeanDefinition for the given parent.
     * @param parentName the name of the parent bean
     * @param cargs the constructor argument values to apply
     * @param pvs the additional property values of the child
     * 構(gòu)造函數(shù),設(shè)置父類,業(yè)務(wù)類構(gòu)造函數(shù)的參數(shù),業(yè)務(wù)類屬性   
     */
    public ChildBeanDefinition(
            String parentName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {

        super(cargs, pvs);
        this.parentName = parentName;
    }

    /**
     * Create a new ChildBeanDefinition for the given parent,
     * providing constructor arguments and property values.
     * @param parentName the name of the parent bean
     * @param beanClass the class of the bean to instantiate
     * @param cargs the constructor argument values to apply
     * @param pvs the property values to apply
     * 構(gòu)造函數(shù),設(shè)置父類,業(yè)務(wù)類beanClass,業(yè)務(wù)類構(gòu)造函數(shù)的參數(shù),業(yè)務(wù)類屬性      
     */
    public ChildBeanDefinition(
            String parentName, Class<?> beanClass, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {

        super(cargs, pvs);
        this.parentName = parentName;
        setBeanClass(beanClass);
    }

    /**
     * Create a new ChildBeanDefinition for the given parent,
     * providing constructor arguments and property values.
     * Takes a bean class name to avoid eager loading of the bean class.
     * @param parentName the name of the parent bean
     * @param beanClassName the name of the class to instantiate
     * @param cargs the constructor argument values to apply
     * @param pvs the property values to apply
     * 構(gòu)造函數(shù),設(shè)置父類,業(yè)務(wù)類名稱,業(yè)務(wù)類構(gòu)造函數(shù)的參數(shù),業(yè)務(wù)類屬性   
     */
    public ChildBeanDefinition(
            String parentName, String beanClassName, ConstructorArgumentValues cargs, MutablePropertyValues pvs) {

        super(cargs, pvs);
        this.parentName = parentName;
        setBeanClassName(beanClassName);
    }

    /**
     * Create a new ChildBeanDefinition as deep copy of the given
     * bean definition.
     * @param original the original bean definition to copy from
     * 構(gòu)造函數(shù),從另一個ChildBeanDefinition進行屬性copy   
     */
    public ChildBeanDefinition(ChildBeanDefinition original) {
        super(original);
    }


    //設(shè)置父類名稱
    @Override
    public void setParentName(@Nullable String parentName) {
        this.parentName = parentName;
    }

    //獲取父類名稱
    @Override
    @Nullable
    public String getParentName() {
        return this.parentName;
    }

    //校驗,會發(fā)現(xiàn),如果沒有父類就會報錯
    @Override
    public void validate() throws BeanDefinitionValidationException {
        super.validate();
        if (this.parentName == null) {
            throw new BeanDefinitionValidationException("'parentName' must be set in ChildBeanDefinition");
        }
    }


    //生成一個新的ChildBeanDefinition,并進行屬性值復(fù)制
    @Override
    public AbstractBeanDefinition cloneBeanDefinition() {
        return new ChildBeanDefinition(this);
    }

    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        }
        if (!(other instanceof ChildBeanDefinition)) {
            return false;
        }
        ChildBeanDefinition that = (ChildBeanDefinition) other;
        return (ObjectUtils.nullSafeEquals(this.parentName, that.parentName) && super.equals(other));
    }

    @Override
    public int hashCode() {
        return ObjectUtils.nullSafeHashCode(this.parentName) * 29 + super.hashCode();
    }

    @Override
    public String toString() {
        return "Child bean with parent '" + this.parentName + "': " + super.toString();
    }

}

? ? ? ?ChildBeanDefinition所有的構(gòu)造方法都要求設(shè)置父類名稱,所以從代碼角度講,它必須依賴于父類存在,不能單獨存在。spring官方當(dāng)初設(shè)置ChildBeanDefinition的初衷就是永遠讓它作為一個子bd存在。但是它現(xiàn)在完全可以被GenericBeanDefinition替代了。

我們來做個總結(jié)吧:

  • RootBeanDefinition作為父bd出現(xiàn),不能作為子bd出現(xiàn)。
  • ChildBeanDefinition必須作為子bd出現(xiàn)。
  • GenericBeanDefinition可以作為父bd出現(xiàn),也可以作為子bd出現(xiàn)。他可以完全替代ChildBeanDefinition,但不能完全替代RootBeanDefinition,這一點在以后的bean合并博文中會講解,盡請期待。

5. AnnotatedBeanDefinition

? ? ? ?現(xiàn)如今,大家都用spring注解掃描的方式進行開發(fā),首先在業(yè)務(wù)類上添加一個注解,比如@Service、@Controller、@Component等,spring掃描所有類并判斷是否加入相關(guān)注解,有注解的類會生成一個BeanDefinition并添加到IOC容器中。我們稱注解BeanDefinition。
? ? ? ?AnnotatedBeanDefinition是一個注解bd的接口,可以獲取BeanDefinition注解相關(guān)數(shù)據(jù)。它有兩個實現(xiàn)類ConfigurationClassBeanDefinition、ScannedGenericBeanDefinition和AnnotatedGenericBeanDefinition。
? ? ? ?AnnotatedBeanDefinition接口源碼很容易理解:

public interface AnnotatedBeanDefinition extends BeanDefinition {
    /**
     * Obtain the annotation metadata (as well as basic class metadata)
     * for this bean definition's bean class.
     * @return the annotation metadata object (never {@code null})
     * 獲取注解信息
     */
    AnnotationMetadata getMetadata();
    /**
     * Obtain metadata for this bean definition's factory method, if any.
     * @return the factory method metadata, or {@code null} if none
     * @since 4.1.1
     * 獲取此beanDefinition的工廠方法的元數(shù)據(jù)(如果有)。
     */
    @Nullable
    MethodMetadata getFactoryMethodMetadata();

}

? ? ? ?這兩個方法是在子類中實現(xiàn)的,我們先查看這兩個方法返回的具體信息:

//業(yè)務(wù)類
@Component
@Description("業(yè)務(wù)類")
@Scope("singleton")
public class InterService {

    private String name;

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

    public String getName() {
        return name;
    }
}

//測試類
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        context.refresh();
        ScannedGenericBeanDefinition beanDefinition = (ScannedGenericBeanDefinition) context.getBeanDefinition("interService");
        //查看spring給我生成的具體BeanDefinition類型
        System.out.println(beanDefinition.getClass().getSimpleName());
        //獲取注解信息
        AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
        //獲取工廠方法元數(shù)據(jù)
        MethodMetadata methodMetadata = beanDefinition.getFactoryMethodMetadata();
        System.out.println();
    }
}

? ? ? ?測試結(jié)果:



? ? ? ?你就理解為存儲了業(yè)務(wù)類的注解信息,便于spring后續(xù)的解析。

6. ScannedGenericBeanDefinition

? ? ? ?有@Component注解的類,會生成ScannedGenericBeanDefinition類型的Bean定義。注意其它繼承了@Component的注解如@Service、@Controller、@Repository也是生成ScannedGenericBeanDefinition類型的Bean定義。
? ? ? ?ScannedGenericBeanDefinition實現(xiàn)了AnnotatedBeanDefinition接口且繼承了GenericBeanDefinition類,scan翻譯成中文就是掃描的意思,顧名思義,它就是spring掃描后生成的BeanDefinition。它的源碼也很容易理解,讀者自行查閱。

7.AnnotatedGenericBeanDefinition

? ? ? ? AnnotatedGenericBeanDefinition在兩種地方會使用。spring啟動時會生成一個AnnotatedBeanDefinitionReader讀取器:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        context.refresh();
        System.out.println(context.getBeanDefinition("interService").getClass().getSimpleName());

        System.out.println();
    }
}
public AnnotationConfigApplicationContext() {
        //在IOC容器中初始化一個 注解bean讀取器AnnotatedBeanDefinitionReader
        this.reader = new AnnotatedBeanDefinitionReader(this);
        //在IOC容器中初始化一個 按類路徑掃描注解bean的 掃描器
        this.scanner = new ClassPathBeanDefinitionScanner(this);
    }
  1. 解析配置類
    主要看這行代碼:
    context.register(Config.class);
    查看以下源碼:context.register(Config.class)->this.reader.register(componentClasses);->registerBean(componentClass);->doRegisterBean(beanClass, null, null, null);->doRegisterBean,最后跟到doRegisterBean方法:
//第一行代碼
        AnnotatedGenericBeanDefinition abd = new AnnotatedGenericBeanDefinition(beanClass);
      .......中間省略........
//最后一行代碼,注冊到IOC容器
        BeanDefinitionReaderUtils.registerBeanDefinition(definitionHolder, this.registry);

看到了碼,spring將你的配置定生成了一個AnnotatedGenericBeanDefinition。
我們來測試一下:

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        context.refresh();
        System.out.println(context.getBeanDefinition("config").getClass().getSimpleName());

        System.out.println();
    }
}

打印結(jié)果:
AnnotatedGenericBeanDefinition
  1. 手動注冊
    其實就跟上面配置類一樣。我們不讓spring自動掃描,我們手動注冊一個業(yè)務(wù)類。
public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        context.refresh();

        //手動注冊一個業(yè)務(wù)類
        context.register(InterService.class);
        System.out.println(context.getBeanDefinition("interService").getClass().getSimpleName());

        System.out.println();
    }
}
打印結(jié)果:
AnnotatedGenericBeanDefinition

總結(jié):通過AnnotatedBeanDefinitionReader手動注冊的類sping都會生成AnnotatedGenericBeanDefinition。而自動掃描的都會生成ScannedGenericBeanDefinition。

8.ConfigurationClassBeanDefinition

? ? ? ?首先需要注意的是,ConfigurationClassBeanDefinition是一個內(nèi)部類,其外部類是ConfigurationClassBeanDefinitionReader,這個類負責(zé)將@Bean注解的方法轉(zhuǎn)換為對應(yīng)的ConfigurationClassBeanDefinition類,源碼就不過多解釋了,和之前幾個BeanDefinition差不多。

默認設(shè)置

  1. 如果@Bean注解沒有指定bean的名字,默認會用方法的名字命名bean。

  2. @Configuration注解的類會成為一個工廠類,而所有的@Bean注解的方法會成為工廠方法,通過工廠方法實例化Bean,而不是直接通過構(gòu)造函數(shù)初始化。

  3. @Bean注解注釋的類會使用構(gòu)造函數(shù)自動裝配。

//在@Configuration注解的類中,使用@Bean注解實例化的Bean,其定義會用ConfigurationClassBeanDefinition存儲。
@Configuration
public class ConfigurationTest {
    @Bean
    public User getUser(){
        return new User();
    }
}

public class User {
    private String name;
}

public class Test {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        //注冊配置類
        context.register(Config.class);
        context.refresh();
        System.out.println(context.getBeanDefinition("getUser").getClass().getSimpleName());
    }
}
image.png

? ? ? ?至此,BeanDefinition整個家族繼承關(guān)系講完了,相信認真讀過這三篇博文的讀者對BeanDefinition都有深入的理解了,建議讀者結(jié)合這三篇博文認真練習(xí),BeanDefinition打好基礎(chǔ)了后續(xù)spring源碼的閱讀才會游刃有余,否則很難讀下去。

? ? ? ?筆者相信,BeanDefinition中的很多屬性大家都不是很理解在spring中到底起了什么作用,這個沒關(guān)系,在后續(xù)源碼學(xué)習(xí)過程中這些屬性的作用會慢慢浮出水面,到時候再回過頭復(fù)習(xí)才會恍然大糊涂。

?著作權(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)容