【源码】Spring —— BeanDefinition 解读1

【源码】Spring —— BeanDefinition 解读1

前言

BeanDefinitionSpring 中对所有 Bean 实例的基础定义信息,一般在 容器 生命周期的很早期就注册了大量的 BeanDefinition,因而后续的各种 Bean 实例依此创建,用官方的话来说 BeanDefinition 就是 bean 的菜单

Spring IoC Container 基于 BeanDefinition 创建 bean,但并不意味着容器中的 bean 就有对应的 BeanDefinition,比如 registerSingleton 方法注册的单例

版本

Spring 5.2.x

BeanDefinition

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	// 单例常量
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;

	// 原型常量
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

	// BeanDefinition 的角色常量定义
	int ROLE_APPLICATION = 0;
	int ROLE_SUPPORT = 1;
	int ROLE_INFRASTRUCTURE = 2;

	//  bean definition 也有“父子”关系
	void setParentName(@Nullable String parentName);
	@Nullable
	String getParentName();

	// bean 实例的类属性指定
	void setBeanClassName(@Nullable String beanClassName);
	@Nullable
	String getBeanClassName();

	// bean 实例的 Scope(作用域)指定
	void setScope(@Nullable String scope);
	@Nullable
	String getScope();

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

	// 该 bean 的初始化依赖哪些 bean(即被依赖 bean 的初始化会先于当前 bean)
	void setDependsOn(@Nullable String... dependsOn);
	@Nullable
	String[] getDependsOn();

	/**
	 * 标记此 bean 是否可以作为被注入的候选对象
	 * 注意,这个标志只影响基于类型的自动装配,也就是说:
	 * 		即使该 bean 没有被标记,按名称自动装配仍然可以被注入
	 */
	void setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate();

	// 针对多个 备选注入 bean 的情况,是否是唯一备选(比如 @Primary 注解)
	void setPrimary(boolean primary);
	boolean isPrimary();

	// 工厂方法对应的 bean 的名称
	void setFactoryBeanName(@Nullable String factoryBeanName);
	@Nullable
	String getFactoryBeanName();

	// 工厂方法名,对应的就是基于工厂方法创建 bean 的模式
	// 比如 @Bean 形式创建的 bean 实例
	void setFactoryMethodName(@Nullable String factoryMethodName);
	@Nullable
	String getFactoryMethodName();

	// 返回构造方法参数,对应 构造方法 注入依赖的模式
	ConstructorArgumentValues getConstructorArgumentValues();
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}

	// 属性值集合,对应 属性 注入依赖的模式
	MutablePropertyValues getPropertyValues();
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	// 初始化回调方法名
	void setInitMethodName(@Nullable String initMethodName);
	@Nullable
	String getInitMethodName();

	// 销毁回调方法名
	void setDestroyMethodName(@Nullable String destroyMethodName);
	@Nullable
	String getDestroyMethodName();

	// 角色设置
	void setRole(int role);
	int getRole();

	// bean definition 描述
	void setDescription(@Nullable String description);
	@Nullable
	String getDescription();

	// 获取对应的 ResolvableType 
	ResolvableType getResolvableType();
	
	// 是否单例
	boolean isSingleton();

	// 是否原型
	boolean isPrototype();
	
	// 是否抽象类
	boolean isAbstract();

	@Nullable
	// BeanDefinition 所在的资源描述信息,报错是提示用
	String getResourceDescription();

	@Nullable
	// 返回被“装饰”的“最近”的 BeanDefinition
	// 比如代理 BeanDefinition 会将 targetBeanDefinition 存放到 decoratedDefinition 属性
	BeanDefinition getOriginatingBeanDefinition();

}

BeanDefinition 的顶层接口,对一个 bean 的描述清单,比如:

  • Classbean 实例的类信息
  • Namebean 实例的名称信息,涉及别名的指定
  • Scopebean 实例的作用域信息,关系到它的生命周期
  • Constructor arguments:以构造方法形式注入依赖时的参数
  • Properties:以属性形式注入依赖时的参数
  • Autowiring mode:自动注入 bean 实例依赖的模式
  • Lazy initialization modebean 实例是否延迟加载
  • Initialization methodinit 回调方法指定
  • Destruction methoddestroy 回调方法指定

拓展

BeanDefinition
如上是 BeanDefinition 的继承图:

  • AbstractBeanDefinition 作为 BeanDefinition 的抽象实现,提供了通用方法的实现
  • RootBeanDefinitionChildBeanDefinition 是一组可以拥有父子关系的 BeanDefinition
  • GenericBeanDefinition 是最通用的 BeanDefinition,它的属性 parentName 同样可以指向父 BeanDefinition
  • AnnotatedBeanDefinitionBeanDefinition 的子接口,它在 BeanDefinition 的基础上提供了 AnnotationMetadata getMetadata() MethodMetadata getFactoryMethodMetadata() 两个方法用于获取 AnnotationMetadataMethodMetadata
  • AnnotatedGenericBeanDefinitionAnnotatedBeanDefinition 的实现,其中 AnnotationMetadataMethodMetadata 的获取直接基于 Class(即对应的 Class 文件必须存在与类路径)
  • ScannedGenericBeanDefinition,不同于前者,AnnotationMetadataMethodMetadata 的获取直接基于 MetadataReader
  • ConfigurationClassBeanDefinition,配置类中 @Bean 方法会被解析为 ConfigurationClassBeanDefinition

示例

public class BeanDefinitionDemo {

    @Component("test")
    public static class A {

        public String name = "default";

        public void a() {
            System.out.println("init ...");
        }

        public String getName() {
            return name;
        }

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

	// 1
    @Test
    public void test() {
        GenericBeanDefinition beanDefinition
                = new GenericBeanDefinition();
        beanDefinition.setBeanClass(A.class);
        // init-method 指定
        beanDefinition.setInitMethodName("a");
        // 属性注入依赖模式
        beanDefinition.setPropertyValues(
                new MutablePropertyValues()
                        .add("name", "dd")
        );

        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext();
        // 注册 bd
        context.registerBeanDefinition("test", beanDefinition);
        // 容器启动时会基于 bd 创建对应的 bean
        context.refresh();
        A bean = context.getBean(A.class);
        System.out.println(bean.name);
    }

	// 2
    @Test
    public void test2() {

        // 元数据解析
        AnnotationMetadata introspect = AnnotationMetadata.introspect(A.class);
        // AnnotatedBeanDefinition 会根据传入的元数据解析 beanClass
        AnnotatedBeanDefinition beanDefinition
                = new AnnotatedGenericBeanDefinition(introspect);
        // 注册 bd,beanName 从注解元数据上解析
        AnnotationMetadata metadata = beanDefinition.getMetadata();
        Map<String, Object> attributes
                = metadata.getAnnotationAttributes("org.springframework.stereotype.Component");
        String beanName = attributes.get("value").toString();

        AnnotationConfigApplicationContext context
                = new AnnotationConfigApplicationContext();
        context.registerBeanDefinition(beanName, beanDefinition);
        // 容器启动时会基于 bd 创建对应的 bean
        context.refresh();
        A bean = context.getBean("test", A.class);
        System.out.println(bean.name);
    }
}

结合两端测试示例理解一下 BeanDefinition

  1. GenericBeanDefinition 的使用,指定 BeanClassInitMethodNamePropertyValues 等属性,构造对应的 bean 实例
  2. AnnotatedBeanDefinition 的使用,可以指定 AnnotationMetadata,基于元数据解析相关属性,比如示例中 beanName 的解析

总结

本章节是对 BeanDefinition 相关类的一个整体梳理,它是一个 使用价值 大于 实现价值 的类,所以下个章节我想结合 Spring 中具体的应用场景来了解 BeanDefinition 如何使用

参考

【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition…)

下一篇:【源码】Spring —— BeanDefinition 解读2


版权声明:本文为weixin_42189048原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>