【小家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需要的信息基本完善


相关文章
|
4月前
|
XML Java 数据格式
Spring IoC容器的设计与实现
Spring 是一个功能强大且模块化的 Java 开发框架,其核心架构围绕 IoC 容器、AOP、数据访问与集成、Web 层支持等展开。其中,`BeanFactory` 和 `ApplicationContext` 是 Spring 容器的核心组件,分别定位为基础容器和高级容器,前者提供轻量级的 Bean 管理,后者扩展了事件发布、国际化等功能。
|
7月前
|
XML Java 数据格式
Spring容器的本质
本文主要讨论Spring容器最核心的机制,用最少的代码讲清楚Spring容器的本质。
|
6月前
|
JSON Java 数据格式
微服务——SpringBoot使用归纳——Spring Boot中的全局异常处理——定义返回的统一 json 结构
本课主要讲解Spring Boot中的全局异常处理方法。在项目开发中,各层操作难免会遇到各种异常,若逐一处理将导致代码耦合度高、维护困难。因此,需将异常处理从业务逻辑中分离,实现统一管理与友好反馈。本文通过定义一个简化的JsonResult类(含状态码code和消息msg),结合全局异常拦截器,展示如何封装并返回标准化的JSON响应,从而提升代码质量和用户体验。
119 0
|
9月前
|
XML Java 数据格式
Spring容器Bean之XML配置方式
通过对以上内容的掌握,开发人员可以灵活地使用Spring的XML配置方式来管理应用程序的Bean,提高代码的模块化和可维护性。
236 6
|
9月前
|
安全 Java 开发者
Spring容器中的bean是线程安全的吗?
Spring容器中的bean默认为单例模式,多线程环境下若操作共享成员变量,易引发线程安全问题。Spring未对单例bean做线程安全处理,需开发者自行解决。通常,Spring bean(如Controller、Service、Dao)无状态变化,故多为线程安全。若涉及线程安全问题,可通过编码或设置bean作用域为prototype解决。
161 1
|
11月前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
10月前
|
前端开发 Java Docker
使用Docker容器化部署Spring Boot应用程序
使用Docker容器化部署Spring Boot应用程序
|
10月前
|
Java Docker 微服务
利用Docker容器化部署Spring Boot应用
利用Docker容器化部署Spring Boot应用
208 0
|
12月前
|
XML 缓存 Java
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
spring源码剖析-spring-beans(内部核心组件,BeanDefinition的注册,BeanWapper创建)
158 10
|
12月前
|
XML 存储 Java
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)
spring源码刨析-spring-beans(内部核心组件,beanDefinition加载过程)