编写我们的丈夫类和妻子类: Husband、Wife
package com.powernode.spring6.bean;
/**
* @author Bonbons
* @version 1.0
*/
public class Husband {
private String name;
private Wife wife;
public void setName(String name) {
this.name = name;
}
public void setWife(Wife wife) {
this.wife = wife;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Husband{" +
"name='" + name + '\'' +
", wife=" + wife.getName() +
'}';
}
}
package com.powernode.spring6.bean;
/**
* @author Bonbons
* @version 1.0
*/
public class Wife {
private String name;
private Husband husband;
public void setName(String name) {
this.name = name;
}
public void setHusband(Husband husband) {
this.husband = husband;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Wife{" +
"name='" + name + '\'' +
", husband=" + husband.getName() +
'}';
}
}
编写我们的XML配置文件 spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--为丈夫类和妻子类分别声明Bean,属性相互调用,作用域采用单例
Singleton + setter 模式的循环依赖
-->
<bean id="husbandBean" class="com.powernode.spring6.bean.Husband" scope="singleton">
<property name="name" value="唐玄宗" />
<property name="wife" ref="wifeBean" />
</bean>
<bean id="wifeBean" class="com.powernode.spring6.bean.Wife" scope="singleton">
<property name="name" value="杨玉环" />
<property name="husband" ref="husbandBean" />
</bean>
</beans>
编写测试方法:CircularDependencyTest
@Test
public void testCD(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
Husband husbandBean = applicationContext.getBean("husbandBean", Husband.class);
Wife wifeBean = applicationContext.getBean("wifeBean", Wife.class);
System.out.println(husbandBean);
System.out.println(wifeBean);
}

我们可以看到,当产生循环依赖,作用域为singleton的时候采用set注入不会产生任何问题
<bean id="husbandBean" class="com.powernode.spring6.bean.Husband" scope="prototype">
<property name="name" value="唐玄宗" />
<property name="wife" ref="wifeBean" />
</bean>
<bean id="wifeBean" class="com.powernode.spring6.bean.Wife" scope="singleton">
<property name="name" value="杨玉环" />
<property name="husband" ref="husbandBean" />
</bean>
编写我们的 Husband 和 Wife 类
package com.powernode.spring6.bean2;
/**
* @author Bonbons
* @version 1.0
*/
public class Husband {
private String name;
private Wife wife;
public Husband(String name, Wife wife) {
this.name = name;
this.wife = wife;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Husband{" +
"name='" + name + '\'' +
", wife=" + wife.getName() +
'}';
}
}
package com.powernode.spring6.bean2;
/**
* @author Bonbons
* @version 1.0
*/
public class Wife {
private String name;
private Husband husband;
public Wife(String name, Husband husband) {
this.name = name;
this.husband = husband;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Wife{" +
"name='" + name + '\'' +
", husband=" + husband.getName() +
'}';
}
}
编写我们的配置文件 spring2.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--采用 singleton + 构造方法注入的模式
Singleton 是在对象创建完之后曝光,然而构造方法注入是在属性赋值结束之后才算完成对象的创建
构造注入产生的循环依赖无法解决
-->
<bean id="h" class="com.powernode.spring6.bean2.Husband">
<!--通过构造方法注入-->
<constructor-arg name="name" value="李隆基" />
<constructor-arg index="1" ref="w" />
</bean>
<bean id="w" class="com.powernode.spring6.bean2.Wife">
<constructor-arg index="0" value="杨贵妃" />
<constructor-arg name="husband" ref="h" />
</bean>
</beans>
编写我们的测试文件 >> Is there an unresolvable circular reference? 【产生的报错信息】
@Test
public void testCD2(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring2.xml");
Husband husband = applicationContext.getBean("h", Husband.class);
Wife wife = applicationContext.getBean("h", Wife.class);
System.out.println(husband);
System.out.println(wife);
}

在DefaultSingletonBeanRegistry中定义了三个Map集合 >> 分别对应一、二、三级缓存
在该类中有这样一个方法addSingletonFactory(),这个方法的作用是:将创建Bean对象的ObjectFactory对象提前曝光

大致流程就是先从一级缓存中找,找不到就去二级缓存中找,再找不到就去三级缓存中获取之前曝光的ObjectFactory对象,通过ObjectFactory对象获取Bean实例,这样就解决了循环依赖的问题。
编写我们的 SomeService 类:包含三个doSome方法
package com.powernode.reflect;
/**
* @author Bonbons
* @version 1.0
*/
public class SomeService {
// 我们提供三个doSome方法
public void doSome(){
System.out.println("无参doSome方法执行");
}
public String doSome(String s){
System.out.println("一个参数doSome方法执行");
return s;
}
public String doSome(String s, int n){
System.out.println("两个参数doSome方法执行");
return s + n;
}
}
不采用反射机制,我们编写一个测试类调用我们的方法
package com.powernode.reflect;
/**
* @author Bonbons
* @version 1.0
*/
public class Test {
public static void main(String[] args) {
// 不使用反射机制 >> 创建对象调用这三个方法
SomeService someService = new SomeService();
someService.doSome();
String res = someService.doSome("王维");
System.out.println(res);
String res1 = someService.doSome("一刀", 999);
System.out.println(res1);
/*
调用一个方法,我们需要知道四个元素:
第一,调用哪个对象
第二,调用对象哪个方法
第三,方法的参数列表
第四,方法的返回值情况
*/
}
}

得出结论 >> 调用哪个对象的哪个方法,传什么参数,返回什么值 【四要素】
采用上面的 SomeService 类,只需要再编写一个测试类 Test2
package com.powernode.reflect;
import java.lang.reflect.Method;
/**
* 我们利用反射机制来调用方法
* @author Bonbons
* @version 1.0
*/
public class Test2 {
public static void main(String[] args) throws Exception{
// 获取类
Class<?> clazz = Class.forName("com.powernode.reflect.SomeService");
/* 获取方法,通过getDeclaredMethods获取的全部方法
我们通过 getDeclaredMethod获取的是我们指定的方法,参数为方法名和对应的参数列表
*/
Method doSome = clazz.getDeclaredMethod("doSome", String.class, int.class);
// 创建类的对象,此处使用的是过时的方法
Object obj = clazz.newInstance();
// 通过调用方法四要素来调用我们的方法
Object retValue = doSome.invoke(obj, "一刀", 999);
System.out.println(retValue);
}
}

总结,使用反射机制的基本步骤 >> 获取类、获取方法、创建对象、调用方法
编写我们的User类
package com.powernode.reflect;
/**
* @author Bonbons
* @version 1.0
*/
public class User {
private String name;
private int age;
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
编写我们的测试方法:
package com.powernode.reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @author Bonbons
* @version 1.0
*/
public class Test4 {
/*
我们要调用set的方法,已知信息如下:
(1) 全限定类名 className
(2) 方法名,propertyName
(3) 方法类型为int
*/
public static void main(String[] args) throws Exception{
// 已知类名
String className = "com.powernode.reflect.User";
// 已知方法名
String propertyName = "age";
// 获取类
Class<?> clazz = Class.forName(className);
// 获取set方法名
String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
// 根据属性名获取属性类型
Field field = clazz.getDeclaredField(propertyName);
// 此处的 int.class >> field.getType(),获取方法
Method ageMethod = clazz.getDeclaredMethod(setMethodName, field.getType());
// 创建对象
Object o = clazz.newInstance();
// 调用方法
ageMethod.invoke(o, 20);
// 输出对象
System.out.println(o);
}
}
Constructor<?> con = clazz.getDeclaredConstructor();
Object o = con.newInstance();
