欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

使用 BeanDefinition 描述 Spring Bean

程序员文章站 2022-10-24 09:11:44
在Java中,一切皆对象。在JDK中使用java.lang.Class来描述类这个对象。在Spring中,存在bean这样一个概念,那Spring又是怎么抽象bean这个概念,用什么类来描述bean这个对象呢? ......

什么是beandefinition

在java中,一切皆对象。在jdk中使用java.lang.class来描述这个对象。

在spring中,存在bean这样一个概念,那spring又是怎么抽象bean这个概念,用什么类来描述bean这个对象呢?spring使用beandefinition来描述bean

beandefinition

使用 BeanDefinition 描述 Spring Bean

beandefinition继承了attributeaccessorbeanmetadataelement接口。在spring中充斥着大量的各种接口,每种接口都拥有不同的能力,某个类实现了某个接口,也就相应的拥有了某种能力。

attributeaccessor

顾名思义,这是一个属性访问者,它提供了访问属性的能力。

使用 BeanDefinition 描述 Spring Bean

beanmetadataelement

beanmetadataelement中只有一个方法,用来获取元数据元素的配置源对象:

public interface beanmetadataelement {
    @nullable
    object getsource();
}

beandefinition

beandefinition接口是spring对bean的抽象。

我们可以从源码中可以看出,spring是怎么描述一个bean

public interface beandefinition extends attributeaccessor, beanmetadataelement {

    /**
     * scope identifier for the standard singleton scope: "singleton".
     * <p>note that extended bean factories might support further scopes.
     *
     * @see #setscope
     */
    string scope_singleton = configurablebeanfactory.scope_singleton;

    /**
     * scope identifier for the standard prototype scope: "prototype".
     * <p>note that extended bean factories might support further scopes.
     *
     * @see #setscope
     */
    string scope_prototype = configurablebeanfactory.scope_prototype;


    /**
     * role hint indicating that a {@code beandefinition} is a major part
     * of the application. typically corresponds to a user-defined bean.
     */
    int role_application = 0;

    /**
     * role hint indicating that a {@code beandefinition} is a supporting
     * part of some larger configuration, typically an outer
     * {@link org.springframework.beans.factory.parsing.componentdefinition}.
     * {@code support} beans are considered important enough to be aware
     * of when looking more closely at a particular
     * {@link org.springframework.beans.factory.parsing.componentdefinition},
     * but not when looking at the overall configuration of an application.
     */
    int role_support = 1;

    /**
     * role hint indicating that a {@code beandefinition} is providing an
     * entirely background role and has no relevance to the end-user. this hint is
     * used when registering beans that are completely part of the internal workings
     * of a {@link org.springframework.beans.factory.parsing.componentdefinition}.
     */
    int role_infrastructure = 2;


    // modifiable attributes

    /**
     * set the name of the parent definition of this bean definition, if any.
     */
    void setparentname(@nullable string parentname);

    /**
     * return the name of the parent definition of this bean definition, if any.
     */
    @nullable
    string getparentname();

    /**
     * specify the bean class name of this bean definition.
     * <p>the class name can be modified during bean factory post-processing,
     * typically replacing the original class name with a parsed variant of it.
     *
     * @see #setparentname
     * @see #setfactorybeanname
     * @see #setfactorymethodname
     */
    void setbeanclassname(@nullable string beanclassname);

    /**
     * return the current bean class name of this bean definition.
     * <p>note that this does not have to be the actual class name used at runtime, in
     * case of a child definition overriding/inheriting the class name from its parent.
     * also, this may just be the class that a factory method is called on, or it may
     * even be empty in case of a factory bean reference that a method is called on.
     * hence, do <i>not</i> consider this to be the definitive bean type at runtime but
     * rather only use it for parsing purposes at the individual bean definition level.
     *
     * @see #getparentname()
     * @see #getfactorybeanname()
     * @see #getfactorymethodname()
     */
    @nullable
    string getbeanclassname();

    /**
     * override the target scope of this bean, specifying a new scope name.
     *
     * @see #scope_singleton
     * @see #scope_prototype
     */
    void setscope(@nullable string scope);

    /**
     * return the name of the current target scope for this bean,
     * or {@code null} if not known yet.
     */
    @nullable
    string getscope();

    /**
     * set whether this bean should be lazily initialized.
     * <p>if {@code false}, the bean will get instantiated on startup by bean
     * factories that perform eager initialization of singletons.
     */
    void setlazyinit(boolean lazyinit);

    /**
     * return whether this bean should be lazily initialized, i.e. not
     * eagerly instantiated on startup. only applicable to a singleton bean.
     */
    boolean islazyinit();

    /**
     * set the names of the beans that this bean depends on being initialized.
     * the bean factory will guarantee that these beans get initialized first.
     */
    void setdependson(@nullable string... dependson);

    /**
     * return the bean names that this bean depends on.
     */
    @nullable
    string[] getdependson();

    /**
     * set whether this bean is a candidate for getting autowired into some other bean.
     * <p>note that this flag is designed to only affect type-based autowiring.
     * it does not affect explicit references by name, which will get resolved even
     * if the specified bean is not marked as an autowire candidate. as a consequence,
     * autowiring by name will nevertheless inject a bean if the name matches.
     */
    void setautowirecandidate(boolean autowirecandidate);

    /**
     * return whether this bean is a candidate for getting autowired into some other bean.
     */
    boolean isautowirecandidate();

    /**
     * set whether this bean is a primary autowire candidate.
     * <p>if this value is {@code true} for exactly one bean among multiple
     * matching candidates, it will serve as a tie-breaker.
     */
    void setprimary(boolean primary);

    /**
     * return whether this bean is a primary autowire candidate.
     */
    boolean isprimary();

    /**
     * specify the factory bean to use, if any.
     * this the name of the bean to call the specified factory method on.
     *
     * @see #setfactorymethodname
     */
    void setfactorybeanname(@nullable string factorybeanname);

    /**
     * return the factory bean name, if any.
     */
    @nullable
    string getfactorybeanname();

    /**
     * specify a factory method, if any. this method will be invoked with
     * constructor arguments, or with no arguments if none are specified.
     * the method will be invoked on the specified factory bean, if any,
     * or otherwise as a static method on the local bean class.
     *
     * @see #setfactorybeanname
     * @see #setbeanclassname
     */
    void setfactorymethodname(@nullable string factorymethodname);

    /**
     * return a factory method, if any.
     */
    @nullable
    string getfactorymethodname();

    /**
     * return the constructor argument values for this bean.
     * <p>the returned instance can be modified during bean factory post-processing.
     *
     * @return the constructorargumentvalues object (never {@code null})
     */
    constructorargumentvalues getconstructorargumentvalues();

    /**
     * return if there are constructor argument values defined for this bean.
     *
     * @since 5.0.2
     */
    default boolean hasconstructorargumentvalues() {
        return !getconstructorargumentvalues().isempty();
    }

    /**
     * return the property values to be applied to a new instance of the bean.
     * <p>the returned instance can be modified during bean factory post-processing.
     *
     * @return the mutablepropertyvalues object (never {@code null})
     */
    mutablepropertyvalues getpropertyvalues();

    /**
     * return if there are property values values defined for this bean.
     *
     * @since 5.0.2
     */
    default boolean haspropertyvalues() {
        return !getpropertyvalues().isempty();
    }

    /**
     * set the name of the initializer method.
     *
     * @since 5.1
     */
    void setinitmethodname(@nullable string initmethodname);

    /**
     * return the name of the initializer method.
     *
     * @since 5.1
     */
    @nullable
    string getinitmethodname();

    /**
     * set the name of the destroy method.
     *
     * @since 5.1
     */
    void setdestroymethodname(@nullable string destroymethodname);

    /**
     * return the name of the destroy method.
     *
     * @since 5.1
     */
    @nullable
    string getdestroymethodname();

    /**
     * set the role hint for this {@code beandefinition}. the role hint
     * provides the frameworks as well as tools with an indication of
     * the role and importance of a particular {@code beandefinition}.
     *
     * @see #role_application
     * @see #role_support
     * @see #role_infrastructure
     * @since 5.1
     */
    void setrole(int role);

    /**
     * get the role hint for this {@code beandefinition}. the role hint
     * provides the frameworks as well as tools with an indication of
     * the role and importance of a particular {@code beandefinition}.
     *
     * @see #role_application
     * @see #role_support
     * @see #role_infrastructure
     */
    int getrole();

    /**
     * set a human-readable description of this bean definition.
     *
     * @since 5.1
     */
    void setdescription(@nullable string description);

    /**
     * return a human-readable description of this bean definition.
     */
    @nullable
    string getdescription();


    // read-only attributes

    /**
     * return whether this a <b>singleton</b>, with a single, shared instance
     * returned on all calls.
     *
     * @see #scope_singleton
     */
    boolean issingleton();

    /**
     * return whether this a <b>prototype</b>, with an independent instance
     * returned for each call.
     *
     * @see #scope_prototype
     * @since 3.0
     */
    boolean isprototype();

    /**
     * return whether this bean is "abstract", that is, not meant to be instantiated.
     */
    boolean isabstract();

    /**
     * return a description of the resource that this bean definition
     * came from (for the purpose of showing context in case of errors).
     */
    @nullable
    string getresourcedescription();

    /**
     * return the originating beandefinition, or {@code null} if none.
     * allows for retrieving the decorated bean definition, if any.
     * <p>note that this method returns the immediate originator. iterate through the
     * originator chain to find the original beandefinition as defined by the user.
     */
    @nullable
    beandefinition getoriginatingbeandefinition();
}

annotatedbeandefinition

annotatedbeandefinition 继承了beandefinition,拓展了beandefinition接口的能力:

使用 BeanDefinition 描述 Spring Bean

beandefinition常见实现类

  • childbeandefinition
  • rootbeandefinition
  • genericbeandefinition
  • annotatedgenericbeandefinition
  • scannedgenericbeandefinition

beandefinitionbuilder

beandefinitionbuilder是builder模式的应用。通过这个类我们可以方便的构建beandefinition的实例对象。举个例子:

@component
public class mybeandefinitionregistrypostprocessor implements beandefinitionregistrypostprocessor {

    @override
    public void postprocessbeandefinitionregistry(beandefinitionregistry registry) throws beansexception {
        beandefinition beandefinition = beandefinitionbuilder.genericbeandefinition(orderservice.class)
                //这里的属性名是根据setter方法
                .addpropertyreference("dao", "orderdao")
                .setinitmethodname("init")
                .setscope(beandefinition.scope_singleton)
                .getbeandefinition();

        registry.registerbeandefinition("orderservice", beandefinition);

    }

    @override
    public void postprocessbeanfactory(configurablelistablebeanfactory beanfactory) throws beansexception {
        //do nothing
    }
}

关于beandefinitionregistrypostprocessor,这里先简单介绍一下,详细的我们后面再说。

beandefinitionregistrypostprocessor继承了beanfactorypostprocessor接口,同时又增加了一个新的方法beandefinitionregistrypostprocessor#postprocessbeandefinitionregistry,该方法允许程序员通过代码编码的方式手动往程序中注册beandefinition

实例中的具体程序已上传到github:https://github.com/shenjianeng/spring-code-study


欢迎关注公众号:

使用 BeanDefinition 描述 Spring Bean