Spring底层原理

BeanFactory和ApplicationContext都可以被称为容器,BeanFactory只负责创建和获取bean

但是ApplicationContext就是调用了BeanFactory的getBean方法。ApplicationContext的getBean方法就是一个门面方法,负责扫描解析配置类,和注册BeanDefinition。功能更全面。就像现实生活中的4S店负责销售,上牌,交税,而bean工厂的就像汽车工厂一样,职责比较单一。

所以单独使用BeanFactroy获取bean是获取不到的。需要自己手动注入BeanDefinition;

在创建容器之前需要先配置bean,可以使用xml的<bean>,也可以使用@Bean,@Component@Import@Configuration等的注解进行配置;将配置的Bean读取成一个BeanDefinition;

一个Bean就会有一个BeanDefinition,所以很多的BeanDefinition也需要有位置存放,所以定义了一个BeanDefinitionMap<key,value>,key就是bean的名字;value就是BeanDefinition。

singletoObjectMap<beanName,bean实例对象>:单例池,所有创建好的单例Bean会存放在单例池中;

所以Spring启动就需要将所有的类都扫描一遍。

  1. BeanFactory生产Bean:工厂生产Bean之前一定要有的BeanDefinition,类似使用说明书。
    1. 生产Bean之前会先判断这个Bean是否已经创建好了;
    2. 如果已经创建好了,会去单例池map中拿取,如果没有创建,就会调用doCreateBean进行实例化。
  2. 实例化:底层就是根据BeanDinfinition中拿到class文件,再通过反射拿到这个Bean机型实例化。 Object obj = class.newInstance();//反射的方式获取这个对象,默认通过无参构造函数。没有无参构造函数,就会调用有参构造函数。
    1. spring的三种实例化方式:
      1. 默认通过无参构造函数
      2. 假如没有无参构造函数,会调用有参构造函数,参数通过Spring容器注入到构造函数中。(其实就是再次调用工厂获取参数bean,会先根据类型找,如果找到多个,再根据名字匹配)(期间会产生循环依赖,构造函数的循环依赖加一个@lazy注解可以解决)循环依赖解决方式,依赖注入的方式
      3. 通过XML配置实例化
  3. 属性注入:解析@Autowried,发现有Autowired的属性,就会再次调用工厂的getBean();
    1.
  4. 初始化:
    1. 初始化前
    2. 初始化: 初始化是确保对象在被使用前处于正确状态的重要步骤。它有助于减少运行时错误,提高代码的可维护性和系统的稳定性。在依赖注入框架中,初始化通常与生命周期回调方法(如@PostConstruct注解的方法)相关联,这些方法在依赖注入完成后被调用,用于执行初始化逻辑。(初始化的init()和构造函数差异,为什么不在构造函数中加载业务逻辑代码,因为有些需要依赖注入的属性还没注入,无法使用,并且如果有多个构造函数,难道业务逻辑要写在多个构造函数中吗?况且在初始化时候已经经过了依赖注入,写业务逻辑代码可以使用,所以我们一个bean如果有写初始化的逻辑可以写在initi()方法然后使用PostConstruct注解)所以Spring专门提供了init()用来初始化方法,方便程序员操作;
      1. 初始化方式三种:通过init-method的XML配置指定方法,PostConstruct,还可以通过实现InitializingBean接口的afterPropertiesSet()方法初始化
    3. 初始化后:BeanPostProcessor.after()提供给程序员进行扩展的工具;AOP也是在此阶段实现的
      1. Aop底层是通过动态代理实现的;关键方法WarpIfNecessary
      2. JDK动态代理:如果实现了接口,使用JDK动态代理;通过实现的方式加反射的机制。Proxy.class代理类 implement 目标类
      3. CGlib动态代理:如果没实现接口,使用CGlib动态代理:通过继承extends方式,子类调用父类。Proxy.class代理类 extends 目标类
      4. JDK8之前反射更慢,所以CGlib更快;但是JDK8之后差不多
  5. 最后将创建完成的单例bean放入到单例池中;
  6. 销毁;

最终通过ApplicationContext去单例池中拿去一个成熟完整的Bean;

Bean的作用域为原型的时候,不会放入单例池中,每次都会创建一个新的Bean;

  1. 类(Class):首先,你需要有一个Java类,这个类定义了你想要创建的对象的结构和行为。这个类可以包含属性、方法等,它是你想要实例化的对象的蓝图。

  2. BeanDefinition:然后,你可以定义一个BeanDefinition,这是一个配置元数据,它告诉Spring框架如何创建和管理这个类的实例。BeanDefinition 可以包含类的全限定名、构造函数参数、属性值、初始化方法、销毁方法等信息。

所以,实际上是先有类,然后才有BeanDefinitionBeanDefinition 是基于类的定义来配置的,它描述了如何创建和管理类的实例。没有类,就没有BeanDefinition 可言。​​​​​​​

相关推荐
sevevty-seven13 分钟前
java重要知识点 JVM基本结构
java·开发语言·jvm
张飞的猪14 分钟前
什么是AOP面向切面编程?怎么简单理解?
java·spring·aop·面向切面编程
TANGLONG22215 分钟前
【初阶数据结构与算法】复杂度分析练习之轮转数组(多种方法)
java·c语言·数据结构·c++·python·算法·面试
墨如初见16 分钟前
vue前端进行AES加密,JAVA对其进行AES解密
java·前端·vue.js
jonyleek17 分钟前
JVS开源框架:工作流引擎代理中心的设计挑战与实现方案
java·gitee·开源·github·软件需求
hi_zf17 分钟前
面试知识目录
java
码蜂窝编程官方20 分钟前
【含开题报告+文档+源码】基于Web的房地产销售网站的设计与实现
java·前端·vue.js·spring boot·spring
提笔惊蚂蚁21 分钟前
java-web-day7-会话跟踪技术
java·开发语言·前端·程序人生
Alina_shu26 分钟前
springboot使用kafka推送数据到服务端,带认证
java·spring boot·kafka
爱吃涮毛肚的肥肥(暂时吃不了版)35 分钟前
Linux高阶——1103—修改屏蔽字&&信号到达及处理流程&&时序竞态问题
linux·运维·服务器·开发语言·c++·后端