Spring(2)-什么是BeanDefinition?

有人穷,就是因为懒,今天看到这句话,我觉得貌似这是在说我,废话少说,今天把那个BeanDefinition的最小化接口看下里面有什么

org.springframework.beans.factory.config.BeanDefinition
public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    /**
     * Scope identifier for the standard singleton scope: {@value}.
     * <p>Note that extended bean factories might support further scopes.
     * @see #setScope
     * @see ConfigurableBeanFactory#SCOPE_SINGLETON
     * scope:单例 singleton
     */
    String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

    /**
     * Scope identifier for the standard prototype scope: {@value}.
     * <p>Note that extended bean factories might support further scopes.
     * @see #setScope
     * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE
     * scope:proptotype,多例
     */
    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.
     * 角色:属于应用程序的bean,用户自定义的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}.
     * 角色:属于框架自身的bean
     */
    int ROLE_INFRASTRUCTURE = 2;


    // Modifiable attributes

    /**
     * Set the name of the parent definition of this bean definition, if any.
     * 设置beanDefinition的parent BeanDefinition
     */
    void setParentName(@Nullable String parentName);

    /**
     * Return the name of the parent definition of this bean definition, if any.
     * parent bean的名字
     */
    @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
     * 设置bean class的名称
     */
    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()
     * 核心属性,此为bean的class名称
     */
    @Nullable
    String getBeanClassName();

    /**
     * Override the target scope of this bean, specifying a new scope name.
     * @see #SCOPE_SINGLETON
     * @see #SCOPE_PROTOTYPE
     * 设置bean的scope作用域
     */
    void setScope(@Nullable String scope);

    /**
     * Return the name of the current target scope for this bean,
     * or {@code null} if not known yet.
     * scope,bean是单例的,还是每次new一个(prototype),就靠它了
     */
    @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.
     * 懒加载bean?默认情况下,都是容器启动时,初始化;这也是官方推荐的,及早发现问题
     * 如果设置了这个值,容器启动时不会初始化对象,首次getBean才初始化对象
     */
    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.
     * 设置依赖的bean,bean工厂将保证首先初始化这些bean。
     */
    void setDependsOn(@Nullable String... dependsOn);

    /**
     * Return the bean names that this bean depends on.
     * 在本bean初始化之前,需要先初始化的bean:注意,这里不是说本bean依赖的其他需要注入的bean
     */
    @Nullable
    String[] getDependsOn();

    /**
     * Set whether this bean is a candidate for getting autowired into some other bean.
     * 基于类型的自动装配
     * 那基于名称和基于类型有什么区别?
     * 假如自动注入一个TestService的接口,那么就会在spring里面找到TestService类型的bean注入进去
     * 当你注入的时候,发现AutowireCandidate属性是false,那么是注入不进去的
     *
     * 当你Autowired的时候,发现TestService接口实现类有多个,不知道注入哪一个
     * 解决1:在某个实现类上打上@Primary注解,就是BeanDefinition的primary属性,那么就会注入这个bean
     * 解决2:在加了@Autowired的注解之上,再加一个@Qualifier注解指定bean name
     * 解决3:使用@Resource注解
     *
     *
     * <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.
     * 是否够资格作为自动注入的候选bean,,,如果这里返回false,那就连自动注入的资格都没得
     */
    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.
     * 当作为依赖,要注入给某个bean时,当有多个候选bean时,本bean是否为头号种子选手,
     * 就像神奇宝贝里面,皮卡丘是小智在战斗时候的头号小精灵
     */
    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.
     * 核心属性,本属性获取工厂bean的名称,getFactoryMethodName获取工厂方法的名称,配合使用,生成
     */
    @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})
     *
     * 通过xml<bean>方法定义bean时,通过<constructor-arg>来定义构造器的参数,这里即:获取构造器参数
     */
    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})
     *
     * 通过xml <bean>方式定义bean时,
     * 通过 <property name="testService" ref="testService"/>
     * 这种方式来注入依赖,这里即:获取property注入的参数值
     */
    MutablePropertyValues getPropertyValues();

    /**
     * Return if there are property 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 an indication of
     * the role and importance of a particular {@code BeanDefinition}.
     * @since 5.1
     * @see #ROLE_APPLICATION
     * @see #ROLE_SUPPORT
     * @see #ROLE_INFRASTRUCTURE
     */
    void setRole(int role);

    /**
     * Get the role hint for this {@code BeanDefinition}. The role hint
     * provides the frameworks as well as tools 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 a resolvable type for this bean definition,
     * based on the bean class or other specific metadata.
     * <p>This is typically fully resolved on a runtime-merged bean definition
     * but not necessarily on a configuration-time definition instance.
     * @return the resolvable type (potentially {@link ResolvableType#NONE})
     * @since 5.2
     * @see ConfigurableBeanFactory#getMergedBeanDefinition
     */
    ResolvableType getResolvableType();

    /**
     * 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.
     * @since 3.0
     * @see #SCOPE_PROTOTYPE
     * 是否prototype
     */
    boolean isPrototype();

    /**
     * Return whether this bean is "abstract", that is, not meant to be instantiated.
     * 是否为抽象的,还记得<bean>方式定义的时候,可以这样指定吗?
     * <bean id="testByPropertyController" class="org.springframework.simple.TestByPropertyController" abstract="true">
     */
    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.
     * <p>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();

}

beanName

这个接口里面没有这东西,但是呢,在使用注解的规则是按照beanClassName的值按照驼峰格式转换来的。

默认是类的路径名+#+0

 

 

在spring的默认实现工厂里面,采用下面的字段存取bean和beanDefinition

org.springframework.beans.factory.support.DefaultListableBeanFactory
/** Map of bean definition objects, keyed by bean name. */
    /**
     * 存放注册BeanDefinition的map
     * key是beanName
     * 默认规则是:beanClassName按驼峰转换后的名字。
     * 初始化容量是256
     */
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

这里的key是beanName,如果是同一个上下文里有两个相同的beanName的beanDefinition呢?

public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"application-context.xml"});
        //默认就是true
        context.setAllowBeanDefinitionOverriding(true);
        context.refresh();
        //注入
        GenericBeanDefinition beanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder.genericBeanDefinition(TestServiceSameKey.class)
                .getBeanDefinition();
        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
        beanFactory.registerBeanDefinition("testService",beanDefinition);
        //获取
        TestServiceSameKey testServiceSameKey = context.getBean(TestServiceSameKey.class);
        testServiceSameKey.doSerivce();
    }

在spring里面默认是可以覆盖beanName相同的BeanDefinition,springboot结果又改成false了

有人就会说,你怎么知道的呢,不会是以讹传讹把,没有啊,下面是Springboot的注释。

 

 

当context.setAllowBeanDefinitionOverriding(false);的时候,结果如下

Exception in thread "main" org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'testService' defined in null: Cannot register bean definition [Generic bean: class [org.spring.learn.service.TestServiceSameKey]; scope=; abstract=false; lazyInit=null; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] for bean 'testService': There is already [Generic bean: class [org.spring.learn.service.TestService]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [application-context.xml]] bound.
at org.springframework.beans.factory.support.DefaultListableBeanFactory.registerBeanDefinition(DefaultListableBeanFactory.java:995)
at org.spring.learn.service.Run.main(Run.java:25)

Process finished with exit code 1

提示说,这里已经存在相同beanName,testService

Scope

默认为singleton,在一个容器里面会有一个bean。prototype,每次去getBean的时候,都会new一个对象出来,这个一般不会在启动的时候初始化,如果写的有问题的话,

在初始化的时候不会报错,在Runtime时候报运行异常。

parentName

指定parentBean的名称,以前基于xml的时候可能会用,现在基于直接注解很少使用了

beanClassName

核心属性,bean的class类型,这里说的实际类型,而一般不是接口的名称,例如,我们的注解是写在具体class上的,及时加接口上,一般也是动态代理技术。

毕竟,创建bean要根据class的元数据来创建(一般是反射)

factoryBeanName、factoryMethodName

如果本bean是通过工厂来创造的,这两个对应的就是工厂bean的名称和工厂方法名称

lazyInit

是否延迟初始化,取值:true,false,default,默认是false。

简单说:true,设置true,启动时不初始化,false,启动时就初始化,官方也是推荐这种方式,有问题及早暴露出来

dependsOn

设置这个bean所依赖的被初始化的bean的名称,bean工厂将保证这些bean首先被初始化

autowireCandidate

设置为false的话,当其他的bean要注入这个bean,是注入不了,没有资格被别人注入。

primary

设置为true的话,举例说就是TestController里面@Autowired注入了TestService,接口实现类有几个,其中打了primary的bean,是优先注入到TestController,不然会报

二义性错误,程序期待注入一个结果有很多个。

ConstructorArgumentValues

构造函数属性值,通过xml<bean>方法定义bean时,通过<constructor-arg>来定义构造器的参数,这里即:获取构造器参数

MutablePropertyValues

property方式set注入属性值,通过xml <bean>方式定义bean时,通过 <property name="testService" ref="testService"/>

原博文链接https://www.cnblogs.com/grey-wolf/p/12051957.html,今天的作业就是都用下上面的属性呢?

posted @ 2021-12-27 14:17  正能量教官  阅读(83)  评论(2编辑  收藏  举报