Spring源码分析之BeanDefinition

前言

我们定义的所有Bean,不管是通过XML文件定义的,或者通过@Component注解定义的,或者通过@Bean注解定义的,
最后都会转换成一系列的BeanDefinition对象,保存到BeanDefinitionRegistry(注册表)中。
BeanDefinition和Bean实例的关系就类似于Java类和Java对象的关系,Spring通过各种来源如XML或JavaConfig来加载BeanDefinition,
后续通过BeanDefinition来创建Bean实例。BeanDefinition中保存了Bean的所有信息,如名称,所属Class,是否延迟加载等。

BeanDefinition定义

BeanDefinition接口定义如下

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

   //默认只提供singleton(单例)和prototype(原型,每次都会创建对象)两种,但也可以扩展
   //如基于web的扩展的scope有request, session
   String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
   String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

   //用户定义的Bean一般使用这个
   int ROLE_APPLICATION = 0;
   //暂时不知道哪里使用
   int ROLE_SUPPORT = 1;
   //Spring内部定义的Bean一般使用这个
   int ROLE_INFRASTRUCTURE = 2;

   //所属父Bean,可以继承父Bean的配置信息
   void setParentName(String parentName);
   String getParentName();

   //Bean的类名称,后续要通过反射来创建Bean实例
   void setBeanClassName(String beanClassName);
   String getBeanClassName();

   //Bean的scope,一般我们自己定义的Bean默认就是singleton
   void setScope(String scope);
   String getScope();

   //设置是否懒加载,默认非懒加载(会在创建ApplicationContext的过程中提前创建Bean,懒加载的话就是在第一次getBean()时创建Bean)
   void setLazyInit(boolean lazyInit);
   boolean isLazyInit();

   //设置该Bean依赖的所有的Bean(这里的依赖不是指属性依赖@Autowire这种),而是约定一种依赖关系,如A依赖B,那么在创建A前必须先创建B
   void setDependsOn(String... dependsOn);
   String[] getDependsOn();

   //设置该Bean是否可以注入到其他Bean中,只对根据类型注入有效,如果根据名称注入,即使这边设置了false也是可以的,默认为true
   void setAutowireCandidate(boolean autowireCandidate);
   boolean isAutowireCandidate();

   //是否为主要,同一接口的多个实现,如果没有指定名字,Spring会优先选择设置primary为true的Bean
   void setPrimary(boolean primary);
   boolean isPrimary();

   // 如果该Bean使用工厂方法来创建,需要指定工厂Bean名称。
   void setFactoryBeanName(String factoryBeanName);
   String getFactoryBeanName();

   //指定工厂类中的工厂方法名称
   void setFactoryMethodName(String factoryMethodName);
   String getFactoryMethodName();

   //构造器参数
   ConstructorArgumentValues getConstructorArgumentValues();

   //Bean中的属性值
   MutablePropertyValues getPropertyValues();

   //是否为singleton
   boolean isSingleton();

   //是否为prototype
   boolean isPrototype();

   //如果这个Bean被设置为abstract,那么不能被实例化,
   boolean isAbstract();
}

相关类图如下

Spring提供了不同类型的BeanDefinition实现,
ScannedGenericBeanDefinition: 扫描@Component注解加载的BeanDefinition。
ConfigurationClassBeanDefinition: 扫描@Configuration注解类下包含@Bean注解的方法加载的BeanDefinition。
GenericBeanDefinition: 通用的BeanDefinition实现。

BeanDefinitionRegistry

相关类图如下

DefaultListableBeanFactory就是IOC容器的最终实现类,既实现了BeanFactory接口,也实现了BeanDefinitionRegistry接口,
所以它不仅是Bean容器,也是BeanDefinition注册表,同时管理Bean和BeanDefinition。

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class TestBeanDefinition {

  public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    BeanDefinitionBuilder definitionBuilder = BeanDefinitionBuilder
        .genericBeanDefinition(UserService.class);
    definitionBuilder.addPropertyValue("username", "lisi");
    for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
      System.out.println(beanDefinitionName);
    }
    System.out.println("==========");
    beanFactory.registerBeanDefinition("userService", definitionBuilder.getBeanDefinition());
    for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {
      System.out.println(beanDefinitionName);
    }
    UserService userService = (UserService) beanFactory.getBean("userService");
    System.out.println(userService.getUsername());//lisi
  }

  @Setter
  @Getter
  @NoArgsConstructor
  @AllArgsConstructor
  public static class UserService {

    private String username;

  }

}

我们可以自己创建一个BeanDefinition,将它注册到BeanDefinitionRegistry,后续BeanFactory就根据BeanDefinition来创建Bean实例。
DefaultListableBeanFactory内部是通过一个ConcurrentHashMap来存储Bean名称和BeanDefinition的对应关系的。

参考

Spring IOC 容器源码分析
RootBeanDefinition与GenericBeanDefinition (转)

posted @ 2022-05-06 15:50  strongmore  阅读(79)  评论(0编辑  收藏  举报