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的实现类。

 

posted @ 2021-12-25 16:43  正能量教官  阅读(250)  评论(1编辑  收藏  举报