spring的beanDefinition是什么

本文探讨了Spring框架中的bean、beanDefinition和class之间的关系。beanDefinition是bean的描述信息,包含了如是否是primary、是否懒加载等属性。Spring通过beanDefinition来创建和初始化bean。在自动扫描过程中,class被转化为beanDefinition。Spring初始化bean时,根据beanDefinition的属性进行判断。文章还提及了beanDefinition在自动注入模型判断中的作用,并指出可以通过实现ImportBeanDefinitionRegistrar接口修改beanDefinition属性,实现对Spring的扩展。

在spring源码中,会涉及到bean和beanDefinition这两个概念,接下来,说下什么是bean,什么是beanDefinition

class、beanDefinition、bean三者的关系

class是我们自己写的类,bean是spring经过自己的一系列处理之后。生成的,我们可以认为bean是spring容器中真正的成品,beanDefinition是对bean的一个描述信息,spring会根据beanDefinition去生成bean,所以三者的关系是:
spring首先将class转换为beanDefinition,然后再将beanDefinition转换为bean
我们通常说,spring可以通过自动扫描,完成bean的实例化,其实这里的自动扫描,是把class文件,通过扫描,转换为beanDefinition

beanDefinition的定义

我们可以看下beanDefinition的定义
在这里插入图片描述
可以看到,一个beanDefinition中,定义了N多个属性和方法,比如:是否是primary、是否是懒加载、dependOn属性、autowireMode自动注入属性等

所以,我们可以简单的认为,spring在扫描class的时候,会根据class文件中的注解等信息,给beanDefinition对象赋值,所以,beanDefinition是对一个类的描述
那spring在真正去初始化、实例化一个bean的时候,直接根据beanDefinition去初始化就可以,比如,在判断这个bean是根据类型注入,还是根据名字注入的时候,就直接判断autowireMode的属性值即可

spring根据beanDefinition进行初始化

org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons

@Override
public void preInstantiateSingletons() throws BeansException {
  if (logger.isDebugEnabled()) {
    logger.debug("Pre-instantiating singletons in " + this);
  }

  // Iterate over a copy to allow for init methods which in turn register new bean definitions.
  // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
  // 1.获取到所有的beanDefinitionName
  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

  // Trigger initialization of all non-lazy singleton beans...
  // 2.依次遍历所有的beanDefinitionName,进行初始化
  for (String beanName : beanNames) {
    // 3.在mergedBeanDefinition的时候,会根据beanName从beanDefinitionMap中获取到beanDefinition,merge之后返回
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
      if (isFactoryBean(beanName)) {
        Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
        if (bean instanceof FactoryBean) {
          final FactoryBean<?> factory = (FactoryBean<?>) bean;
          boolean isEagerInit;
          if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
            isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
                    ((SmartFactoryBean<?>) factory)::isEagerInit,
                getAccessControlContext());
          }
          else {
            isEagerInit = (factory instanceof SmartFactoryBean &&
                ((SmartFactoryBean<?>) factory).isEagerInit());
          }
          if (isEagerInit) {
            getBean(beanName);
          }
        }
      }
      else {
        // 4.这里的getBean()是去开始对beanName对应的bean初始化
        getBean(beanName);
      }
    }
  }
}

这是spring初始化前的一个判断逻辑,在第3点注释中,可以看到,是根据beanDefinition的属性进行判断,判断当前是否是单例、是否是非抽象类等
在第4处注解中,会去真正开始初始化bean,这里就有一个疑问点了,既然在第2点这里已经对beanDefinition进行了merge,为什么在getBean()的时候,不直接传beanDefinition过去,传一个beanName,岂不是还要再根据beanName获取一遍beanDefinition?
这里其实在前面mergeBeanDefinition原理
这篇笔记中有说过,在merge之后,会把beanName和merge之后的beanDefinition存到了一个集合中,在下次再次使用到的时候,就无需再次重新merge,直接从集合中获取即可
上面这个源码我们可以看到,在初始化前,会先根据beanName解析到当前class所对应的beanDefinition信息,然后在初始化的过程中,需要进行一些判断的时候,就直接根据beanDefinition的属性进行判断

自动注入模型的判断

通常说,spring有五种注入模型

/**
	 * Constant that indicates no externally defined autowiring. Note that
	 * BeanFactoryAware etc and annotation-driven injection will still be applied.
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
	int AUTOWIRE_NO = 0;

	/**
	 * Constant that indicates autowiring bean properties by name
	 * (applying to all bean property setters).
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
	int AUTOWIRE_BY_NAME = 1;

	/**
	 * Constant that indicates autowiring bean properties by type
	 * (applying to all bean property setters).
	 * @see #createBean
	 * @see #autowire
	 * @see #autowireBeanProperties
	 */
	int AUTOWIRE_BY_TYPE = 2;

	/**
	 * Constant that indicates autowiring the greediest constructor that
	 * can be satisfied (involves resolving the appropriate constructor).
	 * @see #createBean
	 * @see #autowire
	 */
	int AUTOWIRE_CONSTRUCTOR = 3;

	/**
	 * Constant that indicates determining an appropriate autowire strategy
	 * through introspection of the bean class.
	 * @see #createBean
	 * @see #autowire
	 * @deprecated as of Spring 3.0: If you are using mixed autowiring strategies,
	 * prefer annotation-based autowiring for clearer demarcation of autowiring needs.
	 */
	@Deprecated
	int AUTOWIRE_AUTODETECT = 4;

那spring源码在处理的时候,是怎么判断是哪种注入模型呢?

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
  

  PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

  if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
    MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
    // Add property values based on autowire by name if applicable.
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
      autowireByName(beanName, mbd, bw, newPvs);
    }
    // Add property values based on autowire by type if applicable.
    if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
      autowireByType(beanName, mbd, bw, newPvs);
    }
    pvs = newPvs;
  }
}

上面这个是属性注入源码中的部分代码,我删减了一部分,只看我们要学习的
其实spring在判断当前bean是byName,还是byType,就是根据beanDefinition中的autowireMode属性来判断的,这里所说的byType、byName和@Autowired注解的先根据类型注入,再根据name注入没有关系,不是同一个概念,@Autowired注解属于autowireMode为0的场景下的一个知识点

结论

这里说这个代码,只是为了举个例子,来说明,spring实际在对一个bean进行初始化的时候,是以beanDefinition中的属性信息为准的,所以这也是为什么spring提供了一些扩展机制,去修改beanDefinition属性信息、让程序员自己去注入beanDefinition,举个简单例子,比如说,我想将Test.class的autowireMode从默认值0,修改为1,那我们就可以通过实现ImportBeanDefinitionRegistrar接口,在其registerBeanDefinitions方法中,去修改Test类对应的beanDefinition中的autowireMode属性,为什么可以修改?因为registerBeanDefinitions这个方法有一个入参:BeanDefinitionRegistry,经常看源码的就知道,这个类提供了对beanDefinition进行增、删、改、查的方法,简单而言就是说,spring将root权限交给了程序员

所以:spring很强大,将一切都包装的很好,如果我们想自己去扩展spring,也可以,但是需要知道spring提供了哪些扩展点,以及这些扩展点的执行时机

`BeanDefinition` 是 Spring 框架中的一个核心接口,用于描述 Spring 容器中 Bean 的元数据信息。它定义了 Bean 的配置信息,包括 Bean 的类名、作用域、依赖关系、属性值等。Spring 容器通过解析 `BeanDefinition` 来创建和管理 Bean 实例。 ### 主要作用 1. **抽象 Bean 配置**:将 Bean 的定义(如类名、属性、依赖等)抽象为对象,便于 Spring 容器统一管理。 2. **支持多种配置方式**:无论是 XML 配置、注解配置还是 Java 配置,最终都会转换为 `BeanDefinition` 对象。 3. **动态修改 Bean 定义**:可以在运行时通过编程方式修改 `BeanDefinition`,实现动态 Bean 配置。 ### 核心属性 `BeanDefinition` 接口定义了许多属性,用于描述 Bean 的行为,常见的包括: - `beanClassName`:Bean 的类名。 - `scope`:Bean 的作用域(如 `singleton`、`prototype`)。 - `lazyInit`:是否延迟初始化。 - `dependsOn`:依赖的其他 Bean。 - `propertyValues`:Bean 的属性值。 - `constructorArgumentValues`:构造函数的参数值。 - `initMethodName`:初始化方法名。 - `destroyMethodName`:销毁方法名。 ### 实现类 Spring 提供了多个 `BeanDefinition` 的实现类,常见的有: 1. **`GenericBeanDefinition`**:通用实现,支持动态修改。 2. **`RootBeanDefinition`**:表示一个独立的 Bean 定义,可以合并父 Bean 定义。 3. **`ChildBeanDefinition`**:表示子 Bean 定义,继承父 Bean 定义的属性。 4. **`AnnotatedBeanDefinition`**:支持注解配置的 Bean 定义。 ### 示例代码 以下是一个通过编程方式创建 `GenericBeanDefinition` 的示例: ```java import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.DefaultListableBeanFactory; public class BeanDefinitionExample { public static void main(String[] args) { // 创建 BeanDefinitionRegistry(Spring 容器的一部分) BeanDefinitionRegistry registry = new DefaultListableBeanFactory(); // 创建 GenericBeanDefinition GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); beanDefinition.setBeanClassName("com.example.MyBean"); beanDefinition.setScope("singleton"); // 注册 Bean 定义 registry.registerBeanDefinition("myBean", beanDefinition); // 从容器中获取 Bean MyBean myBean = (MyBean) registry.getBean("myBean"); System.out.println("Bean 获取成功: " + myBean); } } class MyBean { @Override public String toString() { return "This is MyBean"; } } ``` ### 工作流程 1. **解析配置**:Spring 容器在启动时解析配置文件(XML、注解或 Java 配置),将其转换为 `BeanDefinition` 对象。 2. **注册 Bean 定义**:将 `BeanDefinition` 注册到 `BeanDefinitionRegistry` 中。 3. **创建 Bean 实例**:Spring 容器根据 `BeanDefinition` 创建和管理 Bean 实例。 ### 动态修改 Bean 定义 通过 `BeanDefinitionRegistryPostProcessor` 可以动态修改 `BeanDefinition`,例如: ```java import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.context.annotation.BeanDefinitionRegistryPostProcessor; public class CustomBeanDefinitionModifier implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) { // 修改已存在的 Bean 定义 if (registry.containsBeanDefinition("myBean")) { GenericBeanDefinition beanDefinition = (GenericBeanDefinition) registry.getBeanDefinition("myBean"); beanDefinition.setScope("prototype"); // 修改作用域 } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { // 其他配置 } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值