Spring源码学习4:BeanDefinition

BeanDefinition

BeanDefinition里面放着Spring创建bean的过程中所需要的一切原料!

作用

  1. 提升效率:Spring创建一个类是通过反射创建的,创建类的时候需要一些创建信息,比如Class,比如注解信息等等,事先将这些信息缓存起来,在创建bean的时候能够直接从缓存中获取从而达到提升创建效率的目的。
  2. 方便修改:spring创建对象的时候,创建的信息全部是通过 BeanDefinition 内存储的信息来创建对象的,所以,我们可以通过修改BeanDefinition内部特定的值来改变Spring创建对象的结果!
  3. 方便扩展:我们通过一些特定的接口,可以获取到一个类的所有的BeanDefinition信息,从而完成一些特定功能的实现!

番外

扩展点:简单了解一下后面学~

BeanFactoryPostProcessor(工厂后处理器)
BeanPostProcessor(Bean后处理器)

开发时怎么像Spring一样预留扩展点呢?领导老说开个口子以防万一,那么什么是口子?我太菜了不懂~

就比如SpringIOC,加载好BeanDefinition之后,都会调用一个空方法postProcessBeanFactory,入参是应用上下文beanFactory,开发人员实现这个空方法(接口)之后,就可以在空方法里面写自己的代码逻辑,而且入参也提供了所需的数据(或者保存数据的Map),我们就可以灵活的修改数据或者心中数据,以实现自己的特殊需求

源码

注意:并不是标准的源码!有些方法是为了看起来方便加上去的!

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

    作用域相关
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
	void setScope(String scope);
	String getScope();
	boolean isSingleton();
	boolean isPrototype();

	角色类型相关:主要用于区别用户自定义bean还是框架内部bean
	int ROLE_APPLICATION = 0; 表示这个 Bean 是用户自己定义的 Bean
	int ROLE_SUPPORT = 1; 表示这个 Bean 是某些复杂配置的支撑部分
	int ROLE_INFRASTRUCTURE = 2; 表示这是一个 Spring 内部的 Bean
	int getRole();

	配置的父类关系
	void setParentName(String parentName);
	String getParentName();
	
	bean的全限定名
	void setBeanClassName(String beanClassName);
	String getBeanClassName();

	是否懒加载
	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();

	当前bean所依赖的其他bean(使用depends-on属性指定的Bean要先初始化完毕后才初始化当前Beanvoid setDependsOn(String... dependsOn);
	String[] getDependsOn();

	Candidate:候选者,候选者命名规则
	表示当前类是否可以作为一个注入候选者注入到别的bean中
	如果出现NoUniqueBeanDefinitionException异常的原因:没有设置primary=“ture”且所有的候选者autowireCandidate=truevoid setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate();

	是否主要的首选的(当一个接口有多个实现时,且通过btType的形式注入时,会出现NoUniqueBeanDefinitionException异常,此时需要指定一个实现为主要bean,注入就会只注入primary=true”的)
	void setPrimary(boolean primary);
	boolean isPrimary();

	指定用于创建当前bean的工厂bean名称和工厂方法名称
	用于获取已经设置的工厂bean名称和工厂方法名称
	void setFactoryBeanName(String factoryBeanName);
	String getFactoryBeanName();
	void setFactoryMethodName(String factoryMethodName);
	String getFactoryMethodName();
	
	Bean 构造方法的参数,用于实例化 Bean 判断
	AbstractBeanDefinition类中:hasConstructorArgumentValues方法,判断是否有带参构造器。
	ConstructorArgumentValues getConstructorArgumentValues();

 	Bean 属性列表
	MutablePropertyValues getPropertyValues();

	是否抽象的
	boolean isAbstract();
	
	描述信息 类似订单的备注
	String getDescription();
	
	资源描述 还是描述信息 类似订单的商家备注
	String getResourceDescription();
	
	BeanDefinition getOriginatingBeanDefinition();

	Bean 初始化方法 @Bean(initMethod="init")来指定初始化方法 类似 @PostConstruct
    void setInitMethodName(@Nullable String initMethodName);
    String getInitMethodName();

    Bean 销毁方法  @Bean(destroyMethod = "") 类似 @PreDestory
    void setDestroyMethodName(@Nullable String destroyMethodName);
    String getDestroyMethodName();

}

源码说明

1. parentName 说明

ChildBeanDefinition实现类中有这个属性,说明 BeanDefinition 存在父子继承的关系 即类似类里的继承关系 extends

<bean id="parentBean" class="com.example.ParentBean">      <!--父亲-->
    <property name="stringProperty" value="stringValue"/>
</bean>
<bean id="childBean" parent="parentBean">				   <!--儿子-->
    <property name="anotherStringProperty" value="anotherStringValue"/>
</bean>

2. depends-on 说明1

当前bean所依赖的其他bean(使用depends-on属性指定的Bean要先初始化完毕后才初始化当前Bean)

<bean id="helloApi" class="com.feng.spring.chapter2.helloworld.HelloApi">
</bean>
<bean id="decorator" class="cn.javass.spring.chapter3.bean.HelloApiDecorator"  
    depends-on="helloApi">  
    <property name="helloApi"><ref bean="helloApi"/></property>  
</bean>

3. autowireCandidate 说明2

Candidate候选者命名规则:Candidate(候选者)表示当前类是否可以作为一个注入候选者注入到别的bean中!

  • void setAutowireCandidate(boolean autowireCandidate);
  • boolean isAutowireCandidate();

如果出现NoUniqueBeanDefinitionException异常:没有设置primary=“ture”且所有的候选者autowireCandidate=“true”

4. setFactoryBeanName 说明

setFactoryBeanName 和 setFactoryMethodName 在 Spring 框架中用于指定通过哪个工厂bean和工厂方法来创建bean实例。
它们在复杂bean创建逻辑、依赖其他bean的状态或方法的场景中非常有用。
在 Spring 源码中,它们的作用是在bean创建过程中,通过调用指定的工厂方法来创建bean实例。

<!-- 定义工厂bean -->
<bean id="myFactoryBean" class="com.example.MyFactoryBean"/>

<!-- 使用工厂bean来创建其他bean -->
<bean id="myBean" factory-bean="myFactoryBean" factory-method="createInstance"/>
class MyBean {
    // Bean的具体实现
}
package com.example;

public class MyFactoryBean {
    public MyBean createInstance() {
        return new MyBean();
    }
}

Spring源码中创建实体类的时候又是怎么使用factory-beanfactory-method的?

答案: AbstractAutowireCapableBeanFactory 类:这个类负责bean的创建和初始化。以下是其中的一些关键代码段:

protected Object createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // ...省略部分代码...

    // 如果存在工厂bean名称和工厂方法名称,则通过工厂方法创建bean
    if (mbd.getFactoryBeanName() != null) {
        return instantiateUsingFactoryMethod(beanName, mbd, args);
    }

    // ...省略部分代码...
}

instantiateUsingFactoryMethod 方法:这个方法使用工厂方法来实例化bean:

protected Object instantiateUsingFactoryMethod(
    final String beanName, final RootBeanDefinition mbd, @Nullable final Object[] explicitArgs) {
    // ...省略部分代码...

    // 获取工厂bean
    Object factoryBean = getBean(mbd.getFactoryBeanName());

    // 获取工厂方法
    Method factoryMethod = findFactoryMethod(mbd, factoryBean);

    // 调用工厂方法创建bean实例
    return invokeFactoryMethod(beanName, mbd, factoryBean, factoryMethod, explicitArgs);
}

5. setConstructorArgumentValues 说明

把构造函数相关的配置信息,存储到bean定义的ConstructorArgumentValues对象中:

package com.example;

public class MyBean {
    private String name;
    private int age;

    public MyBean(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "MyBean{name='" + name + "', age=" + age + '}';
    }
}

通过编程方式配置BeanDefinition

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.f87i

public class ConstructorArgumentExample {
    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

        // 定义BeanDefinition并设置构造函数参数
        BeanDefinition beanDefinition = BeanDefinitionBuilder
                .genericBeanDefinition(MyBean.class)
                .getBeanDefinition();
        
        ConstructorArgumentValues args = new ConstructorArgumentValues();
        args.addGenericArgumentValue("Test Bean");  // 第一个参数,按类型匹配
        args.addGenericArgumentValue(30);           // 第二个参数,按类型匹配
        beanDefinition.getConstructorArgumentValues().addArgumentValues(args);

        // 注册BeanDefinition
        beanFactory.registerBeanDefinition("myBean", beanDefinition);

        // 获取bean实例
        MyBean myBean = beanFactory.getBean("myBean", MyBean.class);
        System.out.println("Bean instance: " + myBean);

        // 验证构造函数参数
        System.out.println("是否存在有参构造函数:" + beanDefinition.hasConstructorArgumentValues());
        System.out.println("Constructor Arguments: " + beanDefinition.getConstructorArgumentValues().getGenericArgumentValues());
    }
}

Bean instance: MyBean{name='Test Bean', age=30}
是否存在有参构造函数:true
构造函数参数: [ValueHolder{value=Test Bean, type=null, name=null, source=null}, ValueHolder{value=30, type=null, name=null, source=null}]

[
    ValueHolder{
        value=TestBean,     构造函数参数的值
        type=null,          构造函数参数的类型
        name=null,          构造函数参数的名称
        source=null         参数值的来源
    },
    ValueHolder{
        value=30,
        type=null,
        name=null,
        source=null
    }
]

AbstractAutowireCapableBeanFactory 类:在创建bean实例时,Spring容器会检查bean定义是否包含构造函数参数:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
    // 省略部分代码...

    // 如果定义中包含构造函数参数,则使用带参数的构造函数创建bean实例
    if (mbd.hasConstructorArgumentValues() || args != null) {
        return autowireConstructor(beanName, mbd, ctorToUse, argsToUse);
    }

    // 省略部分代码...
}

autowireConstructor 方法:Spring怎么选择构造函数的?3

protected BeanWrapper autowireConstructor(String beanName, RootBeanDefinition mbd, Constructor<?>[] chosenCtors, Object[] explicitArgs) {
    // 省略部分代码...

    ConstructorArgumentValues cargs = mbd.getConstructorArgumentValues();
    // 使用cargs中的参数来选择合适的构造函数并实例化bean

    // 省略部分代码...
}
  1. 存在无参构造函数,且没有 @Autowired注解时使用无参构造器。
  2. 不存在无参构造函数,但存在有参构造函数,并且没有@Autowired注解会报错,添加@Autowired注解就不会报错。
  3. 存在多个构造函数,并且含有无参构造函数,有@Autowired注解 会使用@Autowired注解标注的构造器。
  4. 有多个@Autowired注解会报错,除非全设置为required = false,此时会加载参数最多的构造器。

从上面来看:首先就是看能拿到那些配置信息,如果cargs 里面都没有有参构造,那Spring肯定就是选择使用无参构造来初始化对象!如果cargs 里面有内容,那就看有几个内容,从而选择符合参数数量的构造函数,再结合@Autowired等等…

5.1 ConstructorArgumentValues 类 4

ConstructorArgumentValues: 类用于管理bean定义中的构造函数参数,可以按索引或通用方式添加和获取参数。

ValueHolder内部类: 封装了构造函数参数的具体信息,包括值、类型、名称和来源。


    <bean id="book0" class="demo3.school.Book">
        <constructor-arg name="writer" index="0" type="java.lang.String" value="我爱中国"/>
        <constructor-arg name="isbn" index="1" type="long" value="18888888"/>
        <constructor-arg name="owner" index="2" type="demo3.school.Student" ref="student1"/>
    </bean>

XML配置文件中的信息都记录到ConstructorArgumentValues 中以便Spring使用:

[
    ValueHolder{
        value=我爱中国,     				构造函数参数的值
        type=java.lang.String,          构造函数参数的类型
        name=writer,          			构造函数参数的名称
        source=null         			参数值的来源
    },
    ValueHolder{
        value=18888888,
        type=long,
        name=isbn,
        source=null
    },
    ValueHolder{
        value=student1,
        type=demo3.school.Student,
        name=owner,
        source=null
    }
]

6. getPropertyValues() 说明

该bean定义的一组属性值,这些值会在bean实例化后注入到bean的相应属性中!

6.1 MutablePropertyValues类

MutablePropertyValues类用于存储和管理一组属性值。

主要功能

  • 添加属性值:可以向MutablePropertyValues对象中添加新的属性值。
  • 修改属性值:可以修改现有的属性值。
  • 删除属性值:可以删除现有的属性值。

不需要深究,只需要知道它主要的功能即可,就是一个List,然后对这个List添加修改删除…

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class MutablePropertyValues {

    // 存储PropertyValue对象的列表
    private final List<PropertyValue> propertyValueList;

    // 无参构造函数,初始化空的propertyValueList
    public MutablePropertyValues() {
        this.propertyValueList = new ArrayList<>();
    }

    // 构造函数,通过给定的PropertyValues对象初始化propertyValueList
    public MutablePropertyValues(PropertyValues original) {
        if (original != null) {
            this.propertyValueList = new ArrayList<>(Arrays.asList(original.getPropertyValues()));
        } else {
            this.propertyValueList = new ArrayList<>();
        }
    }

    // 添加或更新PropertyValue对象到propertyValueList中
    public MutablePropertyValues addPropertyValue(PropertyValue pv) {
        for (int i = 0; i < this.propertyValueList.size(); i++) {
            PropertyValue currentPv = this.propertyValueList.get(i);
            // 如果属性名称相同,则更新现有的PropertyValue对象
            if (currentPv.getName().equals(pv.getName())) {
                this.propertyValueList.set(i, pv);
                return this;
            }
        }
        // 如果属性名称不存在,则添加新的PropertyValue对象
        this.propertyValueList.add(pv);
        return this;
    }

    // 通过属性名称和属性值添加PropertyValue对象到propertyValueList中
    public MutablePropertyValues add(String propertyName, Object propertyValue) {
        addPropertyValue(new PropertyValue(propertyName, propertyValue));
        return this;
    }

    // 获取所有PropertyValue对象的数组
    public PropertyValue[] getPropertyValues() {
        return this.propertyValueList.toArray(new PropertyValue[0]);
    }

    // 根据属性名称获取PropertyValue对象
    public PropertyValue getPropertyValue(String propertyName) {
        for (PropertyValue pv : this.propertyValueList) {
            if (pv.getName().equals(propertyName)) {
                return pv;
            }
        }
        return null;
    }

    // 检查是否包含指定属性名称的PropertyValue对象
    public boolean contains(String propertyName) {
        return getPropertyValue(propertyName) != null;
    }

    // 根据属性名称删除PropertyValue对象
    public MutablePropertyValues removePropertyValue(String propertyName) {
        this.propertyValueList.removeIf(pv -> pv.getName().equals(propertyName));
        return this;
    }

    // 检查propertyValueList是否为空
    public boolean isEmpty() {
        return this.propertyValueList.isEmpty();
    }
}


6.2 PropertyValue 类

PropertyValue类用于封装单个属性值,包含属性的名称和对应的值。

public class PropertyValue {

    // 属性的名称
    private final String name;
    
    // 属性的值
    private final Object value;

    // 构造函数,初始化属性名称和属性值
    public PropertyValue(String name, Object value) {
        this.name = name;
        this.value = value;
    }

    // 获取属性名称
    public String getName() {
        return this.name;
    }

    // 获取属性值
    public Object getValue() {
        return this.value;
    }
}

使用案例:

public class PropertyValueExample {
    public static void main(String[] args) {
        // 创建PropertyValue对象,属性名称为"name",属性值为"Test Bean"
        PropertyValue pv = new PropertyValue("name", "Test Bean");

        // 获取并打印属性名称
        System.out.println("Property Name: " + pv.getName());

        // 获取并打印属性值
        System.out.println("Property Value: " + pv.getValue());
    }
}

6.3 Spring源码使用场景

初始化对象后为对象属性值赋值:属性值可以是简单类型,也可以是引用其他bean、集合元素等。因此,需要解析这些属性值,并将解析后的值注入到bean实例中。

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionValueResolver;

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
    // 初始化mpvs变量
    MutablePropertyValues mpvs = null;
    
    // 检查pvs是否是MutablePropertyValues的实例
    if (pvs instanceof MutablePropertyValues) {
        mpvs = (MutablePropertyValues) pvs;
    } else {
        // 如果不是,创建一个新的MutablePropertyValues实例
        mpvs = new MutablePropertyValues(pvs);
    }

    // 创建一个BeanDefinitionValueResolver实例,用于解析属性值中的引用等
    BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, bw);

    // 遍历所有的PropertyValue对象
    for (PropertyValue pv : mpvs.getPropertyValues()) {
        // 获取属性名称
        String propertyName = pv.getName();
        // 获取原始的属性值
        Object originalValue = pv.getValue();
        // 解析属性值(可能是引用、集合元素等)
        Object resolvedValue = valueResolver.resolveValueIfNecessary(propertyName, originalValue);
        // 使用BeanWrapper将解析后的值设置到bean实例中
        bw.setPropertyValue(propertyName, resolvedValue);
    }
}

6.4 番外:简单的认识一下BeanWrapper

  • 在初始化bean的过程中,BeanWrapper用于封装bean的实例。比如我们的JAVA实体类,只有getter、setter方法,Spring怎么知道调用setName、还是setSex。这时候就需要BeanWrapper提供的方法+Bean定义提供的元信息,从而实现为属性赋值的功能,如下:

案例:使用BeanWrapper设置和获取bean属性

public class MyBean {
    private String name;
    private int age;

    // getters and setters
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.MutablePropertyValues;

public class BeanWrapperExample {
    public static void main(String[] args) {
        // 创建一个MyBean实例
        MyBean myBean = new MyBean();

        // 使用BeanWrapper封装MyBean实例
        BeanWrapper beanWrapper = new BeanWrapperImpl(myBean);

        // 设置bean的属性
        beanWrapper.setPropertyValue("name", "Test Bean");
        beanWrapper.setPropertyValue("age", 30);

        // 获取并打印bean的属性
        System.out.println("Bean Name: " + beanWrapper.getPropertyValue("name"));
        System.out.println("Bean Age: " + beanWrapper.getPropertyValue("age"));

        // 使用MutablePropertyValues批量设置属性
        MutablePropertyValues propertyValues = new MutablePropertyValues();
        propertyValues.add("name", "Updated Bean");
        propertyValues.add("age", 35);
        beanWrapper.setPropertyValues(propertyValues);

        // 再次获取并打印bean的属性
        System.out.println("Updated Bean Name: " + beanWrapper.getPropertyValue("name"));
        System.out.println("Updated Bean Age: " + beanWrapper.getPropertyValue("age"));
    }
}

6.5 番外:Environment@ValueMutablePropertyValues

MutablePropertyValues 只要是需要记录属性值:key-value形式的,都可以用他,他就是List,里面一个PropertyValue 就是具体的Entity<key,value>

引用

什么是BeanDefinition!
想要学会Spring源码,你必知必会的BeanDefinition原理!
【Spring】BeanDefinition 源码深度解析


  1. spring的懒加载和depends-on ↩︎

  2. bean中的autowire-candidate又是干什么的? ↩︎

  3. spring bean 初始化时构造函数的选择 ↩︎

  4. Spring中的xml方式构造函数注入小结 ↩︎

  • 24
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值