10Bean的循环依赖+反射机制

A对象中有B属性。B对象中有A属性。这就是循环依赖。我依赖你,你也依赖我。
比如:丈夫类Husband,妻子类Wife。Husband中有Wife的引用。Wife中有Husband的引用。
在这里插入图片描述

package com.sunsplanter.spring6.bean;public class Husband {private String name;private Wife wife;
}
package com.sunsplanter.spring6.bean;public class Wife {private String name;private Husband husband;
}

Spring解决循环依赖的机理十、回顾反射机制

Spring只能解决setter方法注入的单例bean之间的循环依赖。
1.set方法+两个单例Bean存在循环依赖(即ClassA依赖ClassB,ClassB又依赖ClassA,形成依赖闭环):可以解决。Spring在创建ClassA对象后,不需要等给属性赋值,直接将其曝光到bean缓存当中。在解析ClassA的属性时,又发现依赖于ClassB,再次去获取ClassB,当解析ClassB的属性时,又发现需要ClassA的属性,但此时的ClassA已经被提前曝光加入了正在创建的bean的缓存中,则无需创建新的的ClassA的实例,直接从缓存中获取即可。从而解决循环依赖问题。

Spring为什么可以解决set + singleton模式下循环依赖?“提前曝光,往后赋值”
根本的原因在于:这种方式可以做到将“实例化Bean”和“给Bean属性赋值”这两个动作分开去完成。
实例化Bean的时候:调用无参数构造方法来完成。此时可以先不给属性赋值,可以提前将该Bean对象“曝光”给外界。
给Bean属性赋值的时候:调用setter方法来完成。
两个步骤是完全可以分离开去完成的,并且这两步不要求在同一个时间点上完成。
也就是说,Bean都是单例的,我们可以先把所有的单例Bean实例化出来,放到一个集合当中(我们可以称之为缓存),所有的单例Bean全部实例化完成之后,以后我们再慢慢的调用setter方法给属性赋值。这样就解决了循环依赖的问题。

2.set方法+1个单例Bean和1个多例Bean存在循环依赖可以解决,同1。
3.set方法+2个多例Bean存在循环依赖无法解决。Spring只对scope为singleton的Bean提前曝光,多例Bean无法提前曝光
4.。构造方法注入:不论单例、多例,均可能创建对象失败。

测试Set注入解决两个单例Bean存在的循环依赖问题:

package com.circular_dependency;public class Husband {private String name;private Wife wife;public void setName(String name) {this.name = name;}public String getName() {return name;}public void setWife(Wife wife) {this.wife = wife;}// toString()方法重写时需要注意:若直接输出husband,会去调用husband的toString方法,而Husband的toString方法又要输出Wife,转而调用调用Wife的toString方法// 导致出现递归导致的栈内存溢出错误。输出husband.getName()。@Overridepublic String toString() {return "Husband{" +"name='" + name + '\'' +", wife=" + wife.getName() +'}';}
}
package com.circular_dependency;public class Wife {private String name;private Husband husband;public void setName(String name) {this.name = name;}public String getName() {return name;}public void setHusband(Husband husband) {this.husband = husband;}// toString()方法重写时需要注意:若直接输出husband,会去调用husband的toString方法,而Husband的toString方法又要输出Wife,转而调用调用Wife的toString方法// 导致出现递归导致的栈内存溢出错误。输出husband.getName()。@Overridepublic String toString() {return "Wife{" +"name='" + name + '\'' +", husband=" + husband.getName() +'}';}
}

回顾反射机制

1.不使用反射机制调用方法

//用system对象调用login方法登录,成功则boolean为true
boolean success = systemService.login("admin", "admin123");

若不使用反射机制,调用一个方法,一般涉及到4个要素:
● 调用哪个对象的(systemService)
● 哪个方法(login)
● 传什么参数(“admin”, “admin123”)
● 返回什么值(success)


2.1使用反射机制调用方法
假设存在一个类:

public class SystemService {public void logout(){System.out.println("退出系统");}public boolean login(String username, String password){if ("admin".equals(username) && "admin123".equals(password)) {return true;}return false;}public boolean login(String password){if("110".equals(password)){return true;}return false;}
}

目标:获取login(String,String) 方法并调用

第一步:创建对象(四要素之首:调用哪个对象的)。首先需要获取这个类Class。

Class clazz = Class.forName("com.powernode.reflect.SystemService");
//先获取构造方法,用构造方法创建对象
Constructor<?> con = clazz.getDeclaredConstructor();
con.newInstance();

第二步:获取方法login(String,String)(四要素之一:哪个方法)。拿到Class之后,调用getDeclaredMethod()方法可以获取到方法并赋值给loginMethod。

//第二,第三个参数指定方法的参数类型
Method loginMethod = clazz.getDeclaredMethod("login", String.class, String.class);

第三步:调用方法

Object retValue = loginMethod.invoke(obj, "admin", "admin123");

在上述三步中,四要素为:
● 哪个对象:obj
● 哪个方法:loginMethod
● 传什么参数:“admin”, “admin123”
● 返回什么值:retValue

2.2使用反射机制调用set方法给属性赋值
假设有如下类:

package com.sunsplanter.reflect;public class User {private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "User{" +"name='" + name + '\'' +", age=" + age +'}';}
}

知道以下这几条信息:
● 类名是:com.sunsplanter.reflect.User
● 该类中有String类型的name属性和int类型的age属性。
● 另外你也知道该类的设计符合javabean规范。(也就是说属性私有化,对外提供setter和getter方法)

目标:通过反射机制给User对象的name属性赋值zhangsan,给age属性赋值20岁。

package com.sunsplanter.reflect;import java.lang.reflect.Method;public class UserTest {public static void main(String[] args) throws Exception{// 已知类名String className = "com.sunsplanter.reflect.User";// 已知属性名String propertyName = "age";// 创建对象Class<?> clazz = Class.forName(className);Object obj = clazz.newInstance(); // 根据属性名获取setter方法名,而方法名必然符合规范,也即setAge//先将age全部转大写AGE,截取第一个A,再用subString获取age第一个以后的字母ge,一起拼成Age.String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);// 获取MethodMethod setMethod = clazz.getDeclaredMethod(setMethodName, int.class);// 调用MethodsetMethod.invoke(obj, 20);System.out.println(obj);}
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

图像分割实战-系列教程12:deeplab系列算法概述

&#x1f341;&#x1f341;&#x1f341;图像分割实战-系列教程 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在Pycharm中进行 本篇文章配套的代码资源已经上传 1、空洞卷积 图像分割中的传统做法&#xff1a;为了增大感受野&#xff0c;通常都会选择pooling操…

了解VR虚拟现实的沉浸式效果及其技术特点!

VR虚拟现实体验装置作为近年来人气火爆的科技产品&#xff0c;以其独特的沉浸式体验效果吸引了众多用户&#xff0c;那么&#xff0c;你知道这种VR体验装置是如何实现沉浸式体验效果的吗&#xff1f;它又具备了哪些技术特点呢&#xff1f; 一、真实的场景体验 VR虚拟现实技术通…

Windows 环境多个JDK安装与切换

一、下载jdk 去Oracle官网上下载想要安装的jdk版本&#xff0c;https://www.oracle.com/java/technologies/downloads/。 二、安装jdk 双击.exe文件&#xff0c;选择好安装目录进行安装。多个版本的jdk重复这两步操作就好。 三、多版本的jdk都下载安装完成之后&#xff0…

算法实战(一)

基础编程题 题目来源([PAT题目](https://pintia.cn/problem-sets/14/exam/problems/type/6))6-2 多项式求值6-5 求自定类型元素的最大值6-6 求单链表结点的阶乘和6-7 统计某类完全平方数6-9 统计个位数字 题目来源(PAT题目) 6-2 多项式求值 裁判测试程序样例&#xff1a; #in…

【六大排序详解】终篇 :冒泡排序 与 快速排序

终篇 :冒泡排序 与 快速排序 1 冒泡排序1.1 冒泡排序原理1.2 排序步骤1.3 代码实现 2 快速排序2.1 快速排序原理2.1.1 Hoare版本代码实现 2.1.2 hole版本代码实现 2.1.3 前后指针法代码实现 2.1.4 注意取中位数局部优化 2.1.5 非递归版本非递归原理代码实现 2.2 特性总结 谢谢阅…

arm64虚拟化技术与kvm实现原理分享

文章目录 1 简介2 arm64 虚拟化相关硬件支持2.1 arm64 cpu 虚拟化基本原理及硬件支持2.2 系统寄存器捕获和虚拟寄存器支持2.3 VHE 特性支持2.4 内存虚拟化支持2.5 IO 虚拟化支持2.6 DMA 虚拟化支持2.7 中断虚拟化支持2.8 定时器虚拟化支持 3 arm64 kvm 初始化流程3.1 初始化总体…

.NET学习教程一——.net基础定义+VS常用设置

一、定义 .NET分为.NET平台和.NET框架。 .NET平台&#xff08;厨房&#xff09;.NET FrameWork 框架&#xff08;柴米油盐酱醋茶&#xff09; .NET平台&#xff08;中国移动联通平台&#xff09;.NET FrameWork 框架&#xff08;信号塔&#xff09; .NET平台基于.NET Fra…

Ansys Lumerical | 曲面波导锥度(varFDTD 和 FDTD)

附件下载 联系工作人员获取附件 在本例中&#xff0c;我们将使用MODE 2.5D变分FDTD求解器确定SOI锥度的最佳形状。 注意&#xff1a;也可以使用特征模态展开 &#xff08;EME&#xff09; 求解器来模拟此锥度。 我们将首先对这种锥度的设计进行参数化&#xff0c;如下所示&a…

k8s 监控告警终极方案

公众号「架构成长指南」&#xff0c;专注于生产实践、云原生、分布式系统、大数据技术分享 最近一直在搞基于K8S的监控告警平台建设&#xff0c;查找了不少资料&#xff0c;也实验了不少次&#xff0c;目前算是有一定的成果了&#xff0c;分享一下&#xff0c;以下是我们的系统…

SpringBoot 中 @Transactional 注解的使用

一、基本介绍 事务管理是应用系统开发中必不可少的一部分。Spring 为事务管理提供了丰富的功能支持。Spring 事务管理分为编程式和声明式的两种方式。本篇只说明声明式注解。 1、在 spring 项目中, Transactional 注解默认会回滚运行时异常及其子类&#xff0c;其它范…

k8s源码阅读环境配置

源码阅读环境配置 k8s代码的阅读可以让我们更加深刻的理解k8s各组件的工作原理&#xff0c;同时提升我们Go编程能力。 IDE使用Goland&#xff0c;代码阅读环境需要进行如下配置&#xff1a; 从github上下载代码&#xff1a;https://github.com/kubernetes/kubernetes在GOPATH目…

基于JavaWeb+BS架构+SpringBoot+Vue智能停车计费系统的设计和实现

基于JavaWebBS架构SpringBootVue智能停车计费系统的设计和实现 文末获取源码Lun文目录前言主要技术系统设计功能截图订阅经典源码专栏Java项目精品实战案例《500套》 源码获取 文末获取源码 Lun文目录 1 绪 论 1 1.1 研究背景 1 1.2 研究意义 1 1.3 系统主要功能 1 1.4 拟解决…