spring-基础五

BeanDefinition 继承

Java 中继承是其面向对象的基石之一,继承就是之类继承父类的特征与行为,使得子类实例具有父类实例域或方法,或子类从父类继承方法,使得子类具有父类相同的行为.
Spring的继承又是怎样?

bean 定义可以包含很多的配置信息,包括构造函数的参数,属性值,容器的具体信息例如初始化方法,静态工厂方法名,等等。子 bean 的定义继承父定义的配置数据。子定义可以根据需要重写一些值,或者添加其他值。Spring Bean 定义的继承与 Java 类的继承无关,但是继承的概念是一样的。你可以定义一个父 bean 的定义作为模板和其他子 bean 就可以从父 bean 中继承所需的配置。当你使用基于 XML 的配置元数据时,通过使用父属性,指定父 bean 作为该属性的值来表明子 bean 的定义。


官网介绍Bean Definition 最后一句话很重要,可以理解为Spring 所说的继承其实是一种模版的继承,当我们创建实体的时候会使用模版,子类继承父类,其实是子类模版继承父模版,不是java 中单纯的子父类继承关系.子类模版拥有父类模版相关属性行为,并且可以进行覆盖或者重写.

按照官网的示例我们写个简单的demo

    public static void main(String[] args) {
        ClassPathXmlApplicationContext cc = new ClassPathXmlApplicationContext("application_bean.xml");
        TestBeanB child = (TestBeanB) cc.getBean("child");
        System.out.println("child name = " + child.getName());
        System.out.println("child age = " + child.getAge());
    }
    //输出结果
    //child name = override
    //child age = 5

从上面结果中可以看到,子类name值没有被父类覆盖,但是age 覆盖了,也就是说,子类中已经存在的属性不会被父类所覆盖.
Spring的继承其实是一种合并过程,但是需要注意:

  • 子BeanDefinition中的class属性如果为null,同时父BeanDefinition又指定了class属性,那么子BeanDefinition也会继承这个class属性。
  • 子BeanDefinition必须要兼容父BeanDefinition中的所有属性。这是什么意思呢?以我们上面的demo为例,我们在父BeanDefinition中指定了name跟age属性,但是如果子BeanDefinition中子提供了一个name的setter方法,这个时候Spring在启动的时候会报错。因为子BeanDefinition不能承接所有来自父BeanDefinition的属性
BeanDefinition中abstract属性


在xml中并没有指定父类具体类,因此父类被定义成抽象,不能进行实例化,因为它是不完整的,并且它被显示的标记为abstract。当一个定义是abstract,它仅仅作为一个bean定义的模版且父bean定义为子bean定义服务。尝试自己使用这样的抽象父bean,通过将其引用为另一个bean的ref属性或使用父bean ID进行显式的getBean()调用将返回错误。类似地,容器的内部preInstantiateSingletons()方法将忽略定义为抽象的bean定义。

关于BeanDefinition中abstract属性的说明:

  • 并不是作为父BeanDefinition就一定要设置abstract属性为true,abstract只代表了这个BeanDefinition是否要被Spring进行实例化并被创建对应的Bean,如果为true,代表容器不需要去对其进行实例化。
  • 如果一个BeanDefinition被当作父BeanDefinition使用,并且没有指定其class属性。那么必须要设置其abstract为true
  • abstract=true一般会跟父BeanDefinition一起使用,因为当我们设置某个BeanDefinition的abstract=true时,一般都是要将其当作BeanDefinition的模板使用,否则这个BeanDefinition也没有意义,除非我们使用其它BeanDefinition来继承它的属性
  • 默认情况下,ApplicationContext会预先实例化所有单例。因此,重要的是(至少对于单例bean),如果有一个(父)bean定义仅打算用作模板,并且此定义指定了一个类,则必须确保将abstract属性设置为true ,否则应用程序上下文将实际上(试图)预先实例化抽象Bean。
BeanDefinition 方法说明
// 获取父BeanDefinition,主要用于合并
String getParentName();

// 设置的Bean的ClassName
void setBeanClassName(@Nullable String beanClassName);

// Bean的作用域,不考虑web容器,主要两种,单例/原型
void setScope(@Nullable String scope);

// 是否进行懒加载
void setLazyInit(boolean lazyInit);

// 是否需要等待指定的bean创建完之后再创建
void setDependsOn(@Nullable String... dependsOn);

// 是否作为自动注入的候选对象
void setAutowireCandidate(boolean autowireCandidate);

// 是否作为主选的Bean
void setPrimary(boolean primary);

// 创建这个bean的类的名称
void setFactoryBeanName(@Nullable String factoryBeanName);

// 创建这个Bean的方法的名称
void setFactoryMethodName(@Nullable String factoryMethodName);

// 构造函数的参数
ConstructorArgumentValues getConstructorArgumentValues();

// setter方法的参数
MutablePropertyValues getPropertyValues();

// 生命周期回调方法,在Bean完成属性注入后调用
void setInitMethodName(@Nullable String initMethodName);

// 生命周期回调方法,在Bean被销毁时调用
void setDestroyMethodName(@Nullable String destroyMethodName);

// Spring可以对BeanDefinition设置不同的角色,了解即可,不重要
// 用户定义 int ROLE_APPLICATION = 0;
// 某些复杂的配置    int ROLE_SUPPORT = 1;
// 完全内部使用   int ROLE_INFRASTRUCTURE = 2;
void setRole(int role);

// Bean的描述,没有什么实际含义
void setDescription(@Nullable String description);

// 根据scope判断是否是单例
boolean isSingleton();

// 根据scope判断是否是原型
boolean isPrototype();

// 跟合并BeanDefinition相关,如果是abstract,说明会被作为一个父beanDefinition,不用提供class属性
boolean isAbstract();

// Bean的源描述,没有什么实际含义 
String getResourceDescription();

// cglib代理前的BeanDefinition
BeanDefinition getOriginatingBeanDefinition();

参考文档

Spring官网
spring之IOC容器BeanDefinition(bean定义模型)

posted @ 2023-02-03 14:42  年年糕  阅读(14)  评论(0编辑  收藏  举报