手撕spring04源码(A依赖B)

news2024/12/23 20:34:42

概述

本章节优化上一章节通过构造方法实例化对象属性填充问题的痛点,并解决A bean依赖B bean的问题

整体设计

知识点补充

spring生命周期

在Spring中,Bean的生命周期包括实例化、初始化和销毁三个阶段。下面是对每个阶段的解释:

  1. 实例化(Instantiation):在这个阶段,Spring容器会根据配置信息或注解创建Bean的实例。实例化可以通过构造函数实现,也可以通过工厂方法或者工厂Bean来实现。
  2. 初始化(Initialization):在实例化后,Spring会对Bean进行初始化。这个阶段包括以下几个步骤:
    a.属性注入:Spring会将配置的属性值或引用注入到Bean的对应属性中。
    b.实现Aware接口:如果Bean实现了Aware接口,Spring会调用相应的方法,将容器相关的信息注入到Bean中。
    c.自定义初始化方法:如果Bean定义了自定义的初始化方法(通过配置或注解),Spring会在这个阶段调用该方法。
  3. 销毁(Destruction):当容器关闭或者销毁Bean时,会触发销毁阶段。这个阶段包括以下几个步骤:
    a. 实现DisposableBean接口:如果Bean实现了DisposableBean接口,Spring会调用其destroy()方法进行销毁操作。
    b. 自定义销毁方法:如果Bean定义了自定义的销毁方法(通过配置或注解),Spring会在这个阶段调用该方法。

类图

类图

时序图

时序图

  1. 初始化 BeanFactory(DefaultListableBeanFactory)
  2. 注册userDao bean(相关类信息),将注册的类信息放入DefaultListableBeanFactory的map中
  3. 注册userService bean,将注册的类信息(类对象,属性:依赖B)放入DefaultListableBeanFactory的map中
  4. 通过bean工厂获取类的对象
    调用继承了抽象类AbstractAutowireCapableBeanFactory继承的AbstractBeanFactory的getBean方法
    从抽象类AbstractBeanFactory继承的DefaultSingletonBeanRegistry类的getSingleton方法获取类信息
  5. 存在的话返回
  6. 不存在的话从AbstractBeanFactory的子类beanFactory(DefaultListableBeanFactory)中获取bean定义
  7. 从子类BeanFactory(AbstractAutowireCapableBeanFactory)中创建对象
    获取Class类信息(传入无参的构造方法)
    指定Cglib的子类CglibSubclassingInstantiationStrategy通过cglib实例化并返回Object
    将实例化后的对象放到继承的抽象类AbstractBeanFactory继承的DefaultSingletonBeanRegistry类中的map中
    返回实例化后的bean
  8. 返回初始化的bean对象,实例化填充属性
    /**
     * Bean 属性填充
     */
    protected void applyPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
        try {
            PropertyValues propertyValues = beanDefinition.getPropertyValues();
            for (PropertyValue propertyValue : propertyValues.getPropertyValues()) {

                String name = propertyValue.getName();
                Object value = propertyValue.getValue();

                if (value instanceof BeanReference) {
                    // A 依赖 B,获取 B 的实例化
                    BeanReference beanReference = (BeanReference) value;
                    value = getBean(beanReference.getBeanName());
                }
                // 通过反射属性填充
                BeanUtil.setFieldValue(bean, name, value);
            }
        } catch (Exception e) {
            throw new BeansException("Error setting property values:" + beanName);
        }
    }
	从beanDefinition中获取属性信息并遍历,对值为BeanReference对象的,去spring容器中获取对象,过程如上述
	对获取的属性名和值通过cn.hutool.core.bean的beanUtil进行反射设置
  1. 继承的抽象类AbstractBeanFactory继承的DefaultSingletonBeanRegistry类中的map将实例化后的对象放入。统一维护bean对象
  2. 返回bean

小结

A 依赖 B问题:通过继续在DefaultSingletonBeanRegistry中map中获取,不存在的话beanFactory去初始化、实例化该对象并返回给依赖的对象。

问题

A 依赖 B,B 依赖 A这种循环依赖怎么解决?
个人想法:
bean注册的时候,就创建对应的代理Bean,当需要依赖的时候放入代理bean,并去初始化、实例化代理bean

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/727463.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

河南企业级泛域名SSL证书

电脑的普及让网络可以快速发展,紧随网络的发展各个CA认证机构推出了泛域名SSL证书、多域名SSL证书等可以用一张SSL证书保护多个域名网站的SSL数字证书。泛域名SSL证书也叫通配符SSL证书,可以用一张SSL证书保护主域名以及主域名下所有的子域名网站&#x…

NR PDCP(三) data transfer

这篇看下PDCP的data transfer过程,如NR RLC(三) TM and UM mode所述,在UL grant充足的情况下,UM RLC 一直在传输完整的RLC SDU,通过log只能知道UE有在收发data,并不能像LTE似的通过SN去判断UE DL data是否有序接收以及…

平板触控笔要原装的吗?apple pencil的平替笔推荐

如今的电容笔种类越来越多,相信不少人都会在挑选电容笔中踩过坑,例如书写频繁断触,防误触失灵,续航能力欠佳等问题。这样的坑本人也是踩过不少,于是,我决定为大家出一期电容笔详细测评,特意地去…

从程序员的角度看待算法的学习与研究

一:引言 算法的重要性和应用场景: 提高效率:算法可以帮助我们设计和实现高效的解决方案,在有限的资源下,提高计算机程序或系统的执行速度和效率。解决复杂问题:算法可以提供有效的解决方案来解决各种复杂问…

有PMP证书了再考CSPM有必要吗?

先说答案:有必要 首先介绍一下什么是CSPM cspm中文名字是项目管理专业人员能力等级评价,是由中国标准化协会(CAS)组织开展的,它符合国务院发布的《国家标准化发展纲要》,纲要中明确提出要构建多层次从业人…

【mysql】mysql登录密码忘记重置方法,解决password针对mysql8.0及以上版本失效问题

问题场景: 提示:mysql密码忘记 本人场景:mysql装了很久,一段时间未使用,再次打开发现登录不了了,于是想修改密码。 解决方案: 1、找到自己安装mysql的文件夹。删掉其中的data文件夹&#xff…

Python反爬取访问验证处理

最近爬取数据的时候,遇到反爬取限制:即当访问一定次数后会弹出访问验证如下图所示: 这种验证方式没找到绕过去的方法,那就只能用最笨的办法,弹出验证框后,将等待时间延长,然后手动点击验证。代码…

数据结构--线索二叉树的概念

数据结构–线索二叉树的概念 二叉树的中序遍历序列 void InOrder(BiTree T) {if (T ! NULL){InOrder(T->lchild); //递归遍历左子树visit(T); //访问根结点InOrder(T->rchild); //递归遍历右子树} }中序遍历序列:D G B E A F C ①如何找到指定结点p在中序遍历序列中的前…

Oracle-奇怪的expdp备份报错LPX-00217

问题背景: 接用户报障,数据库每天晚上正常的expdp备份,从2天前开始出现奇怪的备份报错LPX-00217: invalid character 3 问题分析: 检查expdp备份的日志,从2天前晚上开始的备份均出现LPX-00217: invalid character 3的报错,报错均…

CentOS7在线安装MySQL新手小白教程

1、下载并安装MySQL官方的 Yum Repository wget -i -c http://dev.mysql.com/get/mysql57-community-release-el7-10.noarch.rpm使用上面的命令下载安装用的Yum Repository yum -y install mysql57-community-release-el7-10.noarch.rpm开始安装MySQL服务器 yum -y install …

C++学习 数组

目录 数组 一维数组 数组名 案例:冒泡排序 二维数组 数组名 数组 数组就是一个集合,里面存放了相同类型的数据元素。 下面的数字对应为数组的下标(索引),可以看到索引范围为0~数组长度-1 特点: 数组中数据元素的数据类型相同。…

github软件包-golang,不同版本的使用--推荐

一、golang中获取github软件包,不同版本(V1,V2...)的使用: github中如何使用: golang语言使用的github的软件包,有时候不同版本如何切换,特别是有的版本变化比较多,例如在v1中没有…

Go语言程序设计(一)Go语言概述及基础

一、前言 为了尽可能获得最佳的运行性能,Go语言被设计成一门静态编译型的语言,而不是动态解释型的。Go语言的编译速度非常快,明显的要快过其他同类语言,比如C和C。 Go语言的官方编译器被称为gc。 Go语言具有以下几个特点&#x…

(css)盒子的阴影

(css)盒子的阴影 效果: 代码: box-shadow: inset 0 0 50px 2px #74eaff;解决参考:https://blog.csdn.net/weixin_52984349/article/details/125803515

docker部署私有化镜像仓库

为什么要部署私有化: 1.防止镜像因为内存不够被驱逐 2.方便内网服务器复用 部署步骤: docker pull registry // 如果嫌麻烦,也可以去我的资源里面去拿现成的,docker load -i registry.tar 到自己的docker里。"""如…

Django搭建图书管理系统02:创建并配置APP功能模块

📁 创建APP **Django中的APP(应用程序)是将功能模块组织在一起的单位,每个APP通常负责处理特定的功能。**开发者可以将不同功能的模块放在不同的app中, 方便代码的复用。app就是项目的基石,因此开发博客的第一步就是创…

[C++] C++11新特性介绍 分析(2): lambda表达式、function包装器、bind()接口

文章目录 [toc] C11**lambda 表达式**lambda 表达式lambda 表达式底层 包装器 functionfunction 包装普通可调用对象function 包装类内成员函数 bind()bind() 使用 及 功能1. 调整参数位置2. 绑定参数 C11 上一篇介绍C11常用的新特性只介绍了一部分. 本篇文章继续分析介绍. l…

Linux简介与安装

文章目录 前言一、Linux简介1.Linux是什么2.学完Linux后能做什么 二、Linux安装1.安装方式介绍2.安装Linux3.网卡设置4.安装SSH连接工具5. Linux目录结构 总结 前言 为了巩固所学的知识,作者尝试着开始发布一些学习笔记类的博客,方便日后回顾。当然&…

括号生成(力扣)递归 JAVA

目录 题目描述:纯递归解法:递归 回溯: 题目描述: 数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。 示例 1: 输入:n 3 输出&#xff1a…

《手把手教你》系列基础篇之1-python+ selenium自动化测试-环境搭建(详细)

1.环境搭建 基于python3和selenium3做自动化测试,俗话说:工欲善其事必先利其器;没有金刚钻就不揽那瓷器活,磨刀不误砍柴工,因此你必须会搭建基本的开发环境,掌握python基本的语法和一个IDE来进行开发&…