Spring BeanDefinition

Spring BeanDefinition

BeanDefinition 包含了我们对 Bean 的配置信息,换言之,Spring 将我们对 Bean 的定义信息进行了抽象,抽象后的实体就是 BeanDefinition,并且Spring 会以此作为标准来创建 Bean 实例

BeanDefinition 创建方式

XmlBeanDefinitionReader 读取

public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 基于 XML 资源 BeanDefinitionReader 实现
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
        String location = "META-INF/beans-context.xml";
        // 基于 ClassPath 加载 XML 资源
        Resource resource = new ClassPathResource(location);
        // 指定字符编码 UTF-8
        EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
        int beanNumbers = beanDefinitionReader.loadBeanDefinitions(encodedResource);
        System.out.println("已加载 BeanDefinition 数量:" + beanNumbers);
        // 通过 Bean Id 和类型进行依赖查找
        User user = beanFactory.getBean("user", User.class);
        System.out.println(user);
    }

PropertiesBeanDefinitionReader 读取(这种方式很少用)

public static void main(String[] args) {
        // 创建 IoC 底层容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // 创建面向 Properties 资源的 BeanDefinitionReader 示例
        PropertiesBeanDefinitionReader beanDefinitionReader = new PropertiesBeanDefinitionReader(beanFactory);
        // Properties 资源加载默认通过 ISO-8859-1,实际存储 UTF-8
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        // 通过指定的 ClassPath 获取 Resource 对象
        Resource resource = resourceLoader.getResource("classpath:/META-INF/user-bean-definitions.properties");
        // 转换成带有字符编码 EncodedResource 对象
        EncodedResource encodedResource = new EncodedResource(resource, "UTF-8");
        int beanDefinitionsCount = beanDefinitionReader.loadBeanDefinitions(encodedResource);
        System.out.println(String.format("已记载 %d 个 BeanDefinition\n", beanDefinitionsCount));
        // 通过依赖查找获取 User Bean
        User user = beanFactory.getBean("user", User.class);
        System.out.println(user);
    }

BeanDefinitionBuilder 方式

    public static void main(String[] args) {
        // 通过 BeanDefinitionBuilder 构建
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        // 属性设置
        beanDefinitionBuilder
                .addPropertyValue("id", 1)
                .addPropertyValue("name", "wyc1856");
        // 获取 BeanDefinition 实例
        BeanDefinition beanDefinition = beanDefinitionBuilder.getBeanDefinition();
    }

BeanDefinition 的方法分析

对于每个字段都会有一个对应的方法,只要知道了字段的含义,方法的含义自然就知道了。

// 获取父BeanDefinition,主要用于合并,下节中会详细分析
String getParentName();

// 对于的bean的ClassName
void setBeanClassName(@Nullable String beanClassName);

// Bean的作用域,不考虑web容器,主要两种,单例/原型,见官网中1.5内容
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可以对bd设置不同的角色,了解即可,不重要
// 用户定义 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();

BeanDefinition 的继承关系

BeanDefinition

AbstractBeanDefinition

  • 该类作为 BeanDefinition 的通用抽象类,实现了大部分的方法,定义了一系列常量并给很多属性赋了默认值。

ChildBeanDefinition

  • 该类在实例化的时候必须要指定一个 parentName,已经被更加灵活的 GenericBeanDefinition 所替代。

GenericBeanDefinition

  • 我们通过注解配置的 bean 以及我们的配置类(除@Bean以外)的 BeanDefinition 类型都是 GenericBeanDefinition。

RootBeanDefinition

  • Spring 在启动时会实例化几个初始化的 BeanDefinition,这几个 BeanDefinition 的类型都为 RootBeanDefinition
  • Spring 在合并 BeanDefinituon 返回的都是 RootBeanDefinition
  • 通过 @Bean 注解配置的 bean 解析出来的 BeanDefinition 都是 RootBeanDefinition(实际上是其子类 ConfigurationClassBeanDefinition

AnnotatedGenericBeanDefinition

  • 通过 AnnotationConfigRegistry 注册的 bean 都是 AnnotatedGenericBeanDefinition
  • 通过 @Import 注解导入的类,最后都是解析为 AnnotatedGenericBeanDefinition

ScannedGenericBeanDefinition

  • 通过注解扫描的类,如 @Service,@Component

ConfigurationClassBeanDefinition

  • 通过 @Bean 注解扫描的类

ClassDerivedBeanDefinition

  • 这个类跟 Kotlin 相关,不是太懂

BeanDefinition 的合并

为啥要合并

  • 扫描阶段子 BeanDefinition 有些属性数缺失的,需要合并父 BeanDefinition 中的属性
  • Spring 本身提供了很多扩展点,在容器启动的时候可能修改 BeanDefinition 的属性,所以每次 getBean的时候需要再合并一次

合并的时机

org.springframework.beans.factory.support.AbstractBeanFactory#getMergedLocalBeanDefinition

扫描阶段

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors --> DefaultListableBeanFactory#getBeanNamesForType

实例化阶段

  • org.springframework.beans.factory.support.DefaultListableBeanFactory#preInstantiateSingletons
  • org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean