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

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【小家Spring】Spring IoC容器中核心定义之------BeanDefinition深入分析(RootBeanDefinition、ChildBeanDefinition...)(中)

抽象实现:AbstractBeanDefinition


AbstractBeanDefinition实现了BeanDefinition定义的一系列操作,定义了描述Bean画像的一系列属性,在AbstractBeanDefinition的基础上,Spring衍生出了一系列具有特殊用途的BeanDefinition。


实现代码非常的多:

public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
    implements BeanDefinition, Cloneable {
  //=====================定义众多常量。这一些常量会直接影响到spring实例化Bean时的策略
  // 个人觉得这些常量的定义不是必须的,在代码里判断即可。Spring定义这些常量的原因很简单,便于维护,让读代码的人知道每个值的意义(所以以后我们在书写代码时,也可以这么来搞)
  //默认的SCOPE,默认是单例
  public static final String SCOPE_DEFAULT = "";
  // 自动装配的一些常量
  public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
  public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
  public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
  public static final int AUTOWIRE_CONSTRUCTOR = AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR;
  @Deprecated
  public static final int AUTOWIRE_AUTODETECT = AutowireCapableBeanFactory.AUTOWIRE_AUTODETECT;
  //检查依赖是否合法,在本类中,默认不进行依赖检查
  public static final int DEPENDENCY_CHECK_NONE = 0; // 不进行检查
  public static final int DEPENDENCY_CHECK_OBJECTS = 1; //如果依赖类型为对象引用,则需要检查
  public static final int DEPENDENCY_CHECK_SIMPLE = 2; //对简单属性的依赖进行检查
  public static final int DEPENDENCY_CHECK_ALL = 3; //对所有属性的依赖进行检查
  //若Bean未指定销毁方法,容器应该尝试推断Bean的销毁方法的名字,目前来说,推断的销毁方法的名字一般为close或是shutdown
  //(即未指定Bean的销毁方法,但是内部定义了名为close或是shutdown的方法,则容器推断其为销毁方法)
  public static final String INFER_METHOD = "(inferred)";
  //=====================属性:基本囊括了Bean实例化需要的所有信息
  //Bean的class对象或是类的全限定名
  @Nullable
  private volatile Object beanClass;
  //默认的scope是单例
  @Nullable
  private String scope = SCOPE_DEFAULT;
  //默认不为抽象类
  private boolean abstractFlag = false;
  //默认不进行自动装配
  private boolean lazyInit = false;
  //默认不是懒加载
  private int autowireMode = AUTOWIRE_NO;
  //默认不进行依赖检查
  private int dependencyCheck = DEPENDENCY_CHECK_NONE;
  // @@DependsOn 默认没有
  @Nullable
  private String[] dependsOn;
  // autowire-candidate属性设置为false,这样容器在查找自动装配对象时,将不考虑该bean,
  // 备注:并不影响本身注入其它的Bean
  private boolean autowireCandidate = true;
  // 默认不是首选的
  private boolean primary = false;
  //用于记录Qualifier,对应子元素qualifier=======这个字段有必要解释一下
  // 唯一向这个字段放值的方法为本类的:public void addQualifier(AutowireCandidateQualifier qualifier)    copyQualifiersFrom这个不算,那属于拷贝
  // 调用处:AnnotatedBeanDefinitionReader#doRegisterBean  但是Spring所有调用处,qualifiers字段传的都是null~~~~~~~~~尴尬
  // 通过我多放跟踪发现,此处这个字段目前【永远】不会被赋值(除非我们手动调用对应方法为其赋值)   但是有可能我才疏学浅,若有知道的  请告知,非常非常感谢  我考虑到它可能是预留字段~~~~
  // 我起初以为这样可以赋值:
  //@Qualifier("aaa")
  //@Service
  //public class HelloServiceImpl   没想到,也是不好使的,Bean定义里面也不会有值
  // 因此对应的方法getQualifier和getQualifiers 目前应该基本上都返回null或者[]
  private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>(0);
  //我理解为通过这个函数的逻辑初始化Bean,而不是构造函数或是工厂方法(相当于自己去实例化,而不是交给Bean工厂)
  @Nullable
  private Supplier<?> instanceSupplier;
  //是否允许访问非public方法和属性,应用于构造函数、工厂方法、init、destroy方法的解析 默认是true,表示啥都可以访问
  private boolean nonPublicAccessAllowed = true;
  // 是否以一种宽松的模式解析构造函数,默认为true(宽松和严格体现在类型匹配上)
  private boolean lenientConstructorResolution = true;
  //工厂类名(注意是String类型,不是Class类型) 对应bean属性factory-method
  @Nullable
  private String factoryBeanName;
  //工厂方法名(注意是String类型,不是Method类型)
  @Nullable
  private String factoryMethodName;
  //记录构造函数注入属性,对应bean属性constructor-arg
  @Nullable
  private ConstructorArgumentValues constructorArgumentValues;
  //Bean属性的名称以及对应的值,这里不会存放构造函数相关的参数值,只会存放通过setter注入的依赖
  @Nullable
  private MutablePropertyValues propertyValues;
  //方法重写的持有者,记录lookup-method、replaced-method元素  @Lookup等
  @Nullable
  private MethodOverrides methodOverrides;
  //init函数的名字
  @Nullable
  private String initMethodName;
  //destory函数的名字
  @Nullable
  private String destroyMethodName;
  //是否执行init-method,程序设置
  private boolean enforceInitMethod = true;
  private boolean enforceDestroyMethod = true;
  //是否是合成类(是不是应用自定义的,例如生成AOP代理时,会用到某些辅助类,这些辅助类不是应用自定义的,这个就是合成类)
  //创建AOP时候为true
  private boolean synthetic = false;
  //Bean的角色,为用户自定义Bean
  private int role = BeanDefinition.ROLE_APPLICATION;
  // Bean的描述信息
  @Nullable
  private String description;
  //the resource that this bean definition came from
  // 这个Bean哪儿来的
  @Nullable
  private Resource resource;
  //=====================方法:就不逐一解释了,大部分都是get、set 只贴出一些特殊的
  // 其实就是给reource赋值了,使用了BeanDefinitionResource
  public void setOriginatingBeanDefinition(BeanDefinition originatingBd) {
    this.resource = new BeanDefinitionResource(originatingBd);
  }
  // 上面有赋值,所以get的时候就是返回上面set进来的值
  public BeanDefinition getOriginatingBeanDefinition() {
    return (this.resource instanceof BeanDefinitionResource ?
        ((BeanDefinitionResource) this.resource).getBeanDefinition() : null);
  }
  //克隆Bean的定义信息
  @Override
  public Object clone() {
    return cloneBeanDefinition();
  }
  public abstract AbstractBeanDefinition cloneBeanDefinition();
}


AbstractBeanDefinition定义了一系列描述Bean画像的属性,通过这个类,可以窥见Bean的某些默认设置(例如默认为单例等)。


从上图可以看出,接下俩需要看具体衍生出来的实现类了,先看RootBeanDefinition、ChildBeanDefinition、GenericBeanDefinition。他们都是AbstractBeanDefinition的直接实现类

GenericBeanDefinition:标准bean definition,通用的


除了具有指定类、可选的构造参数值和属性参数这些其它bean definition一样的特性外,它还具有通过parenetName属性来灵活(动态)设置parent bean definition,而非硬编码作为root bean definition

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(RootConfig.class);
        // 向工厂里注册Bean信息
        GenericBeanDefinition parentBeanDef = new GenericBeanDefinition();
        parentBeanDef.setBeanClass(Parent.class);
        parentBeanDef.setBeanClassName(Parent.class.getName());
        parentBeanDef.setScope(BeanDefinition.SCOPE_SINGLETON);
        // 就这样,我们可以动态的给子Bean 设置一个父Bean进去
        GenericBeanDefinition childBeanDef = new GenericBeanDefinition();
        childBeanDef.setParentName(parentBeanDef.getBeanClassName());
        childBeanDef.setBeanClass(Child.class);
        applicationContext.registerBeanDefinition("parent", parentBeanDef);
        applicationContext.registerBeanDefinition("child", childBeanDef);
        System.out.println(applicationContext.getBeanDefinition("parent"));
        System.out.println(applicationContext.getBeanDefinition("child")); //Generic bean with parent 'com.fsx.bean.Parent': class [com.fsx.bean.Child]; scope=;...
    }


GenericBeanDefinition源码实现非常的的简单,只增加了一个parentName的属性值,其余的实现都在父类AbstractBeanDefinition里


备注:若你是xml配置,最初被加载进来都是一个GenericBeanDefinition,之后再逐渐解析的。


ChildBeanDefinition:子Bean定义信息,依赖于父类RootBeanDefinition


ChildBeanDefinition是一种bean definition,它可以继承它父类的设置,即ChildBeanDefinition对RootBeanDefinition有一定的依赖关系。

(功能和GenericBeanDefinition),所以此处忽略~


从spring 2.5 开始,提供了一个更好的注册bean definition类GenericBeanDefinition,所以以后推荐使用它。


RootBeanDefinition:


一个RootBeanDefinition定义表明它是一个可合并的bean definition:即在spring beanFactory运行期间,可以返回一个特定的bean。但在Spring2.5以后,我们绝大多数情况还是可以使用GenericBeanDefinition来做。


我们非常熟悉的final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);这句代码,就是去合并parent的属性进来,这样体现了继承的强大。属性也才完整。

在 配置文件中可以定义父和子,父用RootBeanDefinition表示, 而子用ChildBeanDefiniton表示,而没有父的就使用 RootBeanDefinition表示。下面看看源码:

//简单的说:在多继承体系中,RootBeanDefinition代表的是当前初始化类的父类的BeanDefinition 若没有父类,那就是它自己嘛
public class RootBeanDefinition extends AbstractBeanDefinition {
  //BeanDefinitionHolder存储有Bean的名称、别名、BeanDefinition
  @Nullable
  private BeanDefinitionHolder decoratedDefinition;
  // AnnotatedElement 是java反射包的接口,通过它可以查看Bean的注解信息
  @Nullable
  private AnnotatedElement qualifiedElement;
  //允许缓存
  boolean allowCaching = true;
  //从字面上理解:工厂方法是否唯一
  boolean isFactoryMethodUnique = false;
  //封装了java.lang.reflect.Type,提供了泛型相关的操作,具体请查看:
  // ResolvableType 可以专题去了解一下子,虽然比较简单 但常见
  @Nullable
  volatile ResolvableType targetType;
  //缓存class,表明RootBeanDefinition存储哪个类的信息
  @Nullable
  volatile Class<?> resolvedTargetType;
  //缓存工厂方法的返回类型
  @Nullable
  volatile ResolvableType factoryMethodReturnType;
  /** Common lock for the four constructor fields below */
  final Object constructorArgumentLock = new Object();
  //缓存已经解析的构造函数或是工厂方法,Executable是Method、Constructor类型的父类
  @Nullable
  Executable resolvedConstructorOrFactoryMethod;
  //表明构造函数参数是否解析完毕
  boolean constructorArgumentsResolved = false;
  //缓存完全解析的构造函数参数
  @Nullable
  Object[] resolvedConstructorArguments;
  //缓存待解析的构造函数参数,即还没有找到对应的实例,可以理解为还没有注入依赖的形参
  @Nullable
  Object[] preparedConstructorArguments;
  /** Common lock for the two post-processing fields below */
  final Object postProcessingLock = new Object();
  //表明是否被MergedBeanDefinitionPostProcessor处理过
  boolean postProcessed = false;
  //在生成代理的时候会使用,表明是否已经生成代理
  @Nullable
  volatile Boolean beforeInstantiationResolved;
  //实际缓存的类型是Constructor、Field、Method类型
  @Nullable
  private Set<Member> externallyManagedConfigMembers;
  //InitializingBean中的init回调函数名——afterPropertiesSet会在这里记录,以便进行生命周期回调
  @Nullable
  private Set<String> externallyManagedInitMethods;
  //DisposableBean的destroy回调函数名——destroy会在这里记录,以便进行生命周期回调
  @Nullable
  private Set<String> externallyManagedDestroyMethods;
  //===========方法(只例举部分)
  // 由此看出,RootBeanDefiniiton是木有父的
  @Override
  public String getParentName() {
    return null;
  }
  @Override
  public void setParentName(@Nullable String parentName) {
    if (parentName != null) {
      throw new IllegalArgumentException("Root bean cannot be changed into a child bean with parent reference");
    }
  }
  // 拿到class类型
  @Nullable
  public Class<?> getTargetType() {
    if (this.resolvedTargetType != null) {
      return this.resolvedTargetType;
    }
    ResolvableType targetType = this.targetType;
    return (targetType != null ? targetType.resolve() : null);
  }
  @Override
  public RootBeanDefinition cloneBeanDefinition() {
    return new RootBeanDefinition(this);
  }
}


可以看到许多与反射相关的对象,这说明spring底层采用的是反射机制


总结一下,RootBeanDefiniiton保存了以下信息:


1.定义了id、别名与Bean的对应关系(BeanDefinitionHolder)


2.Bean的注解(AnnotatedElement)


3.具体的工厂方法(Class类型),包括工厂方法的返回类型,工厂方法的Method对象


4.构造函数、构造函数形参类型


5.Bean的class对象


可以看到,RootBeanDefinition与AbstractBeanDefinition是互补关系,RootBeanDefinition在AbstractBeanDefinition的基础上定义了更多属性,初始化Bean需要的信息基本完善


相关文章
|
11天前
|
Java 测试技术 开发者
Spring IoC容器通过依赖注入机制实现控制反转
【4月更文挑战第30天】Spring IoC容器通过依赖注入机制实现控制反转
21 0
|
10天前
|
Java 开发者 Spring
Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
【5月更文挑战第1天】Spring AOP的切点是通过使用AspectJ的切点表达式语言来定义的。
23 5
|
11天前
|
XML Java 数据格式
如何在Spring AOP中定义和应用通知?
【4月更文挑战第30天】如何在Spring AOP中定义和应用通知?
16 0
|
11天前
|
安全 Java 开发者
在Spring框架中,IoC和AOP是如何实现的?
【4月更文挑战第30天】在Spring框架中,IoC和AOP是如何实现的?
21 0
|
11天前
|
XML Java 程序员
什么是Spring的IoC容器?
【4月更文挑战第30天】什么是Spring的IoC容器?
19 0
|
11天前
|
消息中间件 安全 Java
在Spring Bean中,如何通过Java配置类定义Bean?
【4月更文挑战第30天】在Spring Bean中,如何通过Java配置类定义Bean?
20 1
|
13天前
|
前端开发 Java 数据格式
【Spring系列笔记】定义Bean的方式
在Spring Boot应用程序中,定义Bean是非常常见的操作,它是构建应用程序的基础。Spring Boot提供了多种方式来定义Bean,每种方式都有其适用的场景和优势。
31 2
|
13天前
|
Java Spring 容器
【Spring系列笔记】IOC与DI
IoC 和 DI 是面向对象编程中的两个相关概念,它们主要用于解决程序中的依赖管理和解耦问题。 控制反转是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入和依赖查找。
30 2
|
14天前
|
Java 测试技术 数据库连接
Spring中ioc的优点
总之,Spring中的IoC提供了一种更加灵活、可维护、可测试和可扩展的方式来管理组件之间的依赖关系,从而提高了应用程序的质量和可维护性。这使得开发人员能够更专注于业务逻辑而不是底层的技术细节。
32 1
|
16天前
|
存储 缓存 Java
【spring】06 循环依赖的分析与解决
【spring】06 循环依赖的分析与解决
9 1