• 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,今天的作业就是都用下上面的属性呢?

  • 相关阅读:
    BZOJ 1041: [HAOI2008]圆上的整点
    BZOJ 1040: [ZJOI2008]骑士
    BZOJ 1037: [ZJOI2008]生日聚会Party
    BZOJ 1034: [ZJOI2008]泡泡堂BNB
    BZOJ 1032: [JSOI2007]祖码Zuma
    BZOJ 1031: [JSOI2007]字符加密Cipher
    BZOJ 1030: [JSOI2007]文本生成器
    Flink学习(三) 批流版本的wordcount Scala版本
    Flink学习(三) 批流版本的wordcount JAVA版本
    Flink学习(二) 应用场景和架构模型
  • 原文地址:https://www.cnblogs.com/fuckingPangzi/p/15736071.html
Copyright © 2020-2023  润新知