zoukankan      html  css  js  c++  java
  • Spring(1)什么是BeanDefinition?

    正文

    什么是BeanDefinition呢?

    BeanDefinition,这个东西太重要了,核心的存储结构。

    spring是干什么的,spring刚出来的以后,主打IOC容器,容器是装什么的,bean啊,Bean是什么呢,我也不知道,反正从spring里面拿出来的就是Bean。

    既然你不知道,那你总知道他有什么特征把,这个可以说道说道,

    1、就跟你炸鸡柳,不知道鸡柳是什么,特征是说,黄红色,上面带着酱汁,一般吃就是油炸,香酥脆嫩

    2、或者这么说,一般公司每个季度,员工都要填kqi。姓名,部门,项目,职位啊,等等。

    那Bean呢

    就有abstract(是不是抽象的),lazy-init(是否延迟初始化),true的话就是get获取再去创建对象,默认是false,spring官方支持这种,有问题提前暴露,beanClass,beanClassName(bean class名称),parent(父类)

    ,ConstructorAgumentVlues,PropertiesValuesList,Scope(作用域)singleton,prototype,反射不好搞,就有工厂bean啊,工厂方法啊,role(是框架的,还是应用的),还有挺多的。。。

    既然每个Bean这些特征,这些东西,就是一个模板里面的,基本格式都是固定的,那我们可以来抽象一下,搞个格式出来。

    @Data
    public class SpringBean {
    
        /**
         * bean class 名称
         */
        String beanClassName;
    
        /**
         * 工厂bean的名称
         */
        String factoryBeanName;
    
        /**
         * 工厂方法的名称
         */
        String factoryMethodName;
    
        /**
         * singleton,prototype
         */
        String scope;
    
        /**
         * 是否延迟初始化
         */
        boolean isLazyInit;
    
        /**
         * 依赖的bean
         */
        String[] dependsOn;
    
        /**
         * bean的角色,1框架,2应用
         */
        int role;
    
        /**
         * 是否是主候选bean
         */
        boolean primary;
    
        /**
         * 是不是抽象的
         */
        boolean isAbstract;
        
        .......
    }

    也就是说,就可以根据这样的模板,自己搞一个轻量级的容器出来,是不是,一些轻量级的ioc容器也是这么玩的,那spring肯定不是这么low吧,框架里面的有着扩展性之王的称号,方便我们来替换实现,

    这里该用接口来抽象,肯定要抽象为接口。

    下面去看spring对它的接口描述吧

    A BeanDefinition describes a bean instance, which has property values, constructor argument values, and further information supplied by concrete implementations.
    This is just a minimal interface: The main intention is to allow a BeanFactoryPostProcessor to introspect and modify property values and other bean metadata.
    Since:
    19.03.2004
    See Also:
    ConfigurableListableBeanFactory.getBeanDefinition, org.springframework.beans.factory.support.RootBeanDefinition, org.springframework.beans.factory.support.ChildBeanDefinition
    Author:
    Juergen Hoeller, Rob Harrop

    这里就是说,BeanDefinition 描述了一个Bean实例有的属性值,构造方法值, 尤其声明了:这是一个最小化的接口,主要的目的就是允许BeanFactoryPostProcessor后置处理器

    去修改属性值和其他bean的元数据。2004年的接口,可想而知是多么核心的接口。

    再看看具体定义的方法把,更好的去理解哟:

    /**
         * 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();

    大家仔细看看,可以发现和我们平时定义class的get、set差不多。

    看完之后,look look ,BeanDefinition的实现接口有哪些?

     可以获取注解信息的子接口AnnotatedBeanDefinition

    /**
     * Extended {@link org.springframework.beans.factory.config.BeanDefinition}
     * interface that exposes {@link org.springframework.core.type.AnnotationMetadata}
     * about its bean class - without requiring the class to be loaded yet.
     *
     * @author Juergen Hoeller
     * @since 2.5
     * @see AnnotatedGenericBeanDefinition
     * @see org.springframework.core.type.AnnotationMetadata
     */
    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
         */
        @Nullable
        MethodMetadata getFactoryMethodMetadata();
    
    }

    这个注解可以获取到对应的bean class上面标注的注解元数据

    比如controller

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Component
    public @interface Controller {
    
        /**
         * The value may indicate a suggestion for a logical component name,
         * to be turned into a Spring bean in case of an autodetected component.
         * @return the suggested component name, if any (or empty String otherwise)
         */
        @AliasFor(annotation = Component.class)
        String value() default "";
    
    }

    可以通过AnnotatedBeanDefinition获取到controller注解的value值

    我这里写了一个简单的demo

    @Controller("xxxxxxxxxxxxxxxxx")
    @Service("yyyyyyyyyyyyyyy")
    public class TestController {
    
        @Autowired
        TestService testService;
    
        @Override
        public String toString() {
            return "TestController{" +
                    "testService=" + testService +
                    '}';
        }
    }
    @Slf4j
    public class RunAnnotatedBeanDefinitionTest {
    
        public static void main(String[] args) {
            AnnotationConfigReactiveWebApplicationContext beanFactory = new AnnotationConfigReactiveWebApplicationContext();
            beanFactory.refresh();
            beanFactory.registerBean("yyy",TestController.class,null);
    
            AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) beanFactory.getBeanDefinition("yyy");
            AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();
            Map<String,Object> resultC = annotationMetadata.getAnnotationAttributes("org.springframework.stereotype.Controller");
            Map<String,Object> resultS = annotationMetadata.getAnnotationAttributes("org.springframework.stereotype.Service");
    
            log.info("{}",resultC);
            log.info("{}",resultS);
        }
    }

    我这边打印出来就是:

    16:09:02.923 [main] INFO com.spring.learn.RunAnnotatedBeanDefinitionTest - {value=xxxxxxxxxxxxxxxxx}
    16:09:02.926 [main] INFO com.spring.learn.RunAnnotatedBeanDefinitionTest - {value=yyyyyyyyyyyyyyy}

    AnnotatedBeanDefinition和BeanDefinition接口下的实现类

    实现类都差不多,这是他们的UML图

     基本上AbstractBeanDefinition充当了具体的实现了,差不多都实现了,只有一个方法没实现

    /**
         * Clone this bean definition.
         * To be implemented by concrete subclasses.
         * @return the cloned bean definition object
         */
        public abstract AbstractBeanDefinition cloneBeanDefinition();

    clone这个beanDefinition,不实现就是留着子类扩展,可以放hashmap,可以currentHashMap,可以放redis,等等。

    再看看,org.springframework.beans.factory.support.GenericBeanDefinition,很重要

    public class GenericBeanDefinition extends AbstractBeanDefinition {
    
        @Nullable
        private String parentName;
    
    
        /**
    * 我刚看还没注意,这个有点类似builder模式,再创建一个实例,再往里面设置各种属性值各种set
    * Create a new GenericBeanDefinition, to be configured through its bean * properties and configuration methods. * @see #setBeanClass * @see #setScope * @see #setConstructorArgumentValues * @see #setPropertyValues */ public GenericBeanDefinition() { super(); } /** * Create a new GenericBeanDefinition as deep copy of the given * bean definition. * @param original the original bean definition to copy from */ public GenericBeanDefinition(BeanDefinition original) { super(original); } @Override public void setParentName(@Nullable String parentName) { this.parentName = parentName; } @Override @Nullable public String getParentName() { return this.parentName; } @Override public AbstractBeanDefinition cloneBeanDefinition() { return new GenericBeanDefinition(this); } }

     再看两个spring-beans包里的,org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition

    public class AnnotatedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
    
        private final AnnotationMetadata metadata;
    
        @Nullable
        private MethodMetadata factoryMethodMetadata;
    
    
        /**
         * Create a new AnnotatedGenericBeanDefinition for the given bean class.
         * @param beanClass the loaded bean class
         */
        public AnnotatedGenericBeanDefinition(Class<?> beanClass) {
            setBeanClass(beanClass);
            this.metadata = AnnotationMetadata.introspect(beanClass);
        }
    
        /**
         * Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
         * allowing for ASM-based processing and avoidance of early loading of the bean class.
         * Note that this constructor is functionally equivalent to
         * {@link org.springframework.context.annotation.ScannedGenericBeanDefinition
         * ScannedGenericBeanDefinition}, however the semantics of the latter indicate that a
         * bean was discovered specifically via component-scanning as opposed to other means.
         * @param metadata the annotation metadata for the bean class in question
         * @since 3.1.1
         */
        public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata) {
            Assert.notNull(metadata, "AnnotationMetadata must not be null");
            if (metadata instanceof StandardAnnotationMetadata) {
                setBeanClass(((StandardAnnotationMetadata) metadata).getIntrospectedClass());
            }
            else {
                setBeanClassName(metadata.getClassName());
            }
            this.metadata = metadata;
        }
    
        /**
         * Create a new AnnotatedGenericBeanDefinition for the given annotation metadata,
         * based on an annotated class and a factory method on that class.
         * @param metadata the annotation metadata for the bean class in question
         * @param factoryMethodMetadata metadata for the selected factory method
         * @since 4.1.1
         */
        public AnnotatedGenericBeanDefinition(AnnotationMetadata metadata, MethodMetadata factoryMethodMetadata) {
            this(metadata);
            Assert.notNull(factoryMethodMetadata, "MethodMetadata must not be null");
            setFactoryMethodName(factoryMethodMetadata.getMethodName());
            this.factoryMethodMetadata = factoryMethodMetadata;
        }
    
    
        @Override
        public final AnnotationMetadata getMetadata() {
            return this.metadata;
        }
    
        @Override
        @Nullable
        public final MethodMetadata getFactoryMethodMetadata() {
            return this.factoryMethodMetadata;
        }
    
    }

    就是多了获取bean class的注解功能

     再看看org.springframework.context.annotation.ScannedGenericBeanDefinition

    /**
     * Extension of the {@link org.springframework.beans.factory.support.GenericBeanDefinition}
     * class, based on an ASM ClassReader, with support for annotation metadata exposed
     * through the {@link AnnotatedBeanDefinition} interface.
     *
     * <p>This class does <i>not</i> load the bean {@code Class} early.
     * It rather retrieves all relevant metadata from the ".class" file itself,
     * parsed with the ASM ClassReader. It is functionally equivalent to
     * {@link AnnotatedGenericBeanDefinition#AnnotatedGenericBeanDefinition(AnnotationMetadata)}
     * but distinguishes by type beans that have been <em>scanned</em> vs those that have
     * been otherwise registered or detected by other means.
     *
     * @author Juergen Hoeller
     * @author Chris Beams
     * @since 2.5
     * @see #getMetadata()
     * @see #getBeanClassName()
     * @see org.springframework.core.type.classreading.MetadataReaderFactory
     * @see AnnotatedGenericBeanDefinition
     */
    @SuppressWarnings("serial")
    public class ScannedGenericBeanDefinition extends GenericBeanDefinition implements AnnotatedBeanDefinition {
    
        private final AnnotationMetadata metadata;
    
    
        /**
         * Create a new ScannedGenericBeanDefinition for the class that the
         * given MetadataReader describes.
         * @param metadataReader the MetadataReader for the scanned target class
         */
        public ScannedGenericBeanDefinition(MetadataReader metadataReader) {
            Assert.notNull(metadataReader, "MetadataReader must not be null");
            this.metadata = metadataReader.getAnnotationMetadata();
            setBeanClassName(this.metadata.getClassName());
            setResource(metadataReader.getResource());
        }
    
    
        @Override
        public final AnnotationMetadata getMetadata() {
            return this.metadata;
        }
    
        @Override
        @Nullable
        public MethodMetadata getFactoryMethodMetadata() {
            return null;
        }
    
    }

    一看差不多,这个注解上面使用asm去获取注解信息,差别就是

    org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition,在beans包下面,使用反射

    org.springframework.context.annotation.ScannedGenericBeanDefinition,在context包下面,使用asm

    再看看 org.springframework.beans.factory.support.RootBeanDefinition(spring-beans包下面),这个类里面有个子类,在context包下面(org.springframework.context.annotation

    org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.ConfigurationClassBeanDefinition,应该是和@Configuration注解有莫大关系。

    搞个练习,去使用一下,AnnotatedBeanDefinition的实现类。

  • 相关阅读:
    ie用document.getElementsByName获取不到
    js_设置光标到文本的最后位置
    js-转大小写
    mysql查询数据表的路径
    myeclipse导出javadoc时特殊字符 尖括号
    keyCode码集合
    mysql查询数据库约束
    oracle查询每个表的占用空间
    MYSQL复制表
    MacOs上的Intellij idea高频快捷键总结(2018.1版本)
  • 原文地址:https://www.cnblogs.com/fuckingPangzi/p/15730915.html
Copyright © 2011-2022 走看看