深入理解Spring(一)BeanDefinition接口

写在前言:

本内容是自学过程中进行的重点内容记录,用到的图片,术语来源于网络博客、视频术语、书本当中。个人只是自我的理解和总结归纳。

版权声明:本文为CSDN博主「shadow?s」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/java_lyvee/article/details/102633067   源码编译链接:Spring源码下载编译阅读_zjssoul的博客-CSDN博客

一、JavaBean和SpringBean的区别

  1. SpringBean是通过Spring容器来初始化的对象,SpringBean具有Spring的生命周期,但SpringBean一定是JavaBean,但JavaBean不一定是SpringBean,JavaBean可自己创建。

二、JavaBean的创建过程:

  1. 编译:工程通过javac将若干个.java文件编译成.class文件存储在磁盘中。
  2. 加载:启动Java进程,启动Jvm虚拟机,将磁盘上的.class文件加载到Jvm内存中(方法区)。通过双亲委派机制选择类加载器根据.class文件创建该类的Class类信息(模板)。
  3. 分配空间:Jvm在堆内存中为该对象分配空间,分配的方式可以采用指针碰撞或者空闲列表的方式。
  4. 创建:创建出对象,将引用指向栈内存中的变量。

三、SpringBean的创建过程:

  • 第一步:启动Spring容器开始扫描需要注入的Bean:当Spring容器启动的时候会去调用ConfigurationClassPostProcessor这个bean工厂的后置处理器完成扫描,把需要创建的类信息读取到,比如:类名称、构造、添加了那些注解等等,
  • 第二步:将扫描到的Bean信息存储在BeanDefinition的子类中:Spring记录这些信息使用的是BeanDefinition的子类来存储。BeanDefinition接口中提供了很多属性(具有默认值)和方法,比如:isLazy、dependsOn、Description等。常用的是BeanDefinition接口的实现类:GenericBeanDefinitionRootBeanDefinition。Spring将扫描到的Bean的信息存储在BeanDefinition的子类对象中。每当扫描到一个SpringBean,就会对应的生产一个BeanDefinition。
  • 第三步:构建SpringBean和BeanDefinition的Map集合(beanDefinitionMap):Spring会将每一个SpringBean的名字和这个Bean对应的BeanDefinition对象存储在一个Map中,其中key就是这个SpringBean的名称,value就是这个bean对应的BeanDefinition对象,这个对象中包含了这个SpringBean的所有信息。这个Map存储在ConfigurableListableBeanFactory 接口工厂中,实现类是DefaultListableBeanFactory,这个Bean中定义了一个Map<String, BeanDefinition> beanDefinitionMap。理解:工厂中定义一个Map,工厂来生产Bean,然后将生产的所有Bean都存储在Map中。所以在扩展的时候参数为工厂接口。
  • 第四步:后置工厂的可扩展性:当Spring将类和所对应的BeanDefinition对象存储在map之后,Spring会调用Bean工厂的后置处理器什么叫bean工厂后置处理器?在spring的代码级别中是用一个接口来表示BeanFactoryPostProcessor,只要实现这个接口便是一个bean工厂后置处理器了,BeanFactoryPostProcessor的详细源码解析后面文章再来分析,这里先说一下他的基本作用。BeanFactoryPostProcessor接口在spring内部也有实现,比如第①步当中完成扫描功能的类ConfigurationClassPostProcessor便是一个spring自己实现的bean工厂后置处理器,这个类是阅读spring源码当中最重要的类,没有之一;他完成的功能太多了,以后我们一一分析,先看一下这个类的类结构图。

  1. ConfigurationClassPostProcessor实现了很多接口,和本文有关的只需关注两个接口BeanDefinitionRegistryPostProcessorBeanFactoryPostProcessor;但是由于BeanDefinitionRegistryPostProcessor是继承了BeanFactoryPostProcessor所以读者也可以理解这是一个接口,但是笔者更加建议你理解成两个接口比较合适,因为spring完成上述①②③步的功能就是调用BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法完成的,到了第④步的时候spring是执行BeanFactoryPostProcessor的postProcessBeanFactory方法;这里可能说的有点绕,大概意思spring完成①②③的功能是调用ConfigurationClassPostProcessor的BeanDefinitionRegistryPostProcessor的postProcessBeanDefinitionRegistry方法,到了第④步spring首先会调用ConfigurationClassPostProcessor的BeanFactoryPostProcessor的postProcessBeanFactory的方法,然后在调用程序员提供的BeanFactoryPostProcessor的postProcessBeanFactory方法,所以上图当中第④步我画的是红色虚线,因为第④步可能没有(如果程序员没有提供自己的BeanFactoryPostProcessor;当然这里一定得说明,即使程序员没有提供自己扩展的BeanFactoryPostProcessor,spring也会执行内置的BeanFactoryPostProcessor也就是ConfigurationClassPostProcessor,所以上图画的并不标准,少了一步;即spring执行内置的BeanFactoryPostProcessor;
  2. 重点:我们用自己的话总结一下BeanFactoryPostProcessor的执行时机(不管内置的还是程序员提供)Ⅰ:如果是直接实现BeanFactoryPostProcessor的类是在spring完成扫描类之后(所谓的扫描包括把类变成beanDefinition然后put到map之中),在实例化bean(第⑤步)之前执行;Ⅱ:如果是实现BeanDefinitionRegistryPostProcessor接口的类;虽然这种也叫bean工厂后置处理器他的执行时机是在执行直接实现BeanFactoryPostProcessor的类之前,和扫描(上面①②③步)是同期执行;假设你的程序扩展一个功能,需要在这个时期做某个功能则可以实现这个接口;但是笔者至今没有遇到这样的需求,如果以后遇到或者看到再来补上;(mybatis的最新代码里面便是扩展BeanDefinitionRegistryPostProcessor类来实现的);
  3. 实现BeanFacotryPostProcessor接口,重写接口中的方法,传入对象是一个工厂,工厂有存储Spring单例池缓存的Map属性。
    @FunctionalInterface
    public interface BeanFactoryPostProcessor {
    
    	/**
    	 * Modify the application context's internal bean factory after its standard
    	 * initialization. All bean definitions will have been loaded, but no beans
    	 * will have been instantiated yet. This allows for overriding or adding
    	 * properties even to eager-initializing beans.
    	 * @param beanFactory the bean factory used by the application context
    	 * @throws org.springframework.beans.BeansException in case of errors
    	 */
    	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
    
    }

  • 第五步:Spring单例缓存池Map:Spring在创建单例对象时,先会去Spring的单例缓存池中查询,这个对象是否存在,如果不存在才会创建单例对象。这个单例缓存池存在于:DefaultSingletonBeanRegistry类中singletonObjects,这个Map是线程安全的。
     
    /** Cache of singleton objects: bean name to bean instance. */
    	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);


四、Spring单例Bean创建过程中的几个问题

  1. Spring创建单例对象时,为什么先要去单例缓存池中判断是否存在?按理来说新创建缓存池不可能存在的

五、@PostConstruct:生命周期的初始化回调方法

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值