Spring循环依赖

Bean的初始化阶段的步骤比较复杂,所以着重研究Bean的初始化阶段

Spring Bean的初始化过程涉及如下几个过程:

  • Bean实例化的属性填充

  • Aware接口属性注入

  • BeanPostProcess的before()方法回调

  • InitializingBean接口的初始化方法回调

  • 自定义初始化方法回调

  • BeanPostProcessor的after()方法回调

 Spring在进行属性注入时,会分为以下几种情况:

  • 注入普通属性,String、int或存储基本类型的集合时,直接通过set方法的反射设置进去;

  • 注入单向对象引用属性时,从容器中getBean获取后通过set方法反射进去,如果容器中没有,则先创建被注入对象Bean实例(完成整个生命周期)后,在进行注入操作;

  • 注入双向对象引用属性时,就比较复杂了,涉及了循环依赖;

循环依赖

含义:指两个或多个Bean之间有相互依赖关系,并且形成闭环。

循环依赖会导致Bean无法被实例化,程序运行时会出现异常;

解决方案:Spring提供了三级缓存存储完整的Bean实例和半成品Bean实例,

三级缓存:

一级缓存:SingletonBeanRegistry,最终存储单例Bean成品的容器,即实例化和初始化都完成的Bean;

二级缓存:EarlySingletonObjects,早期Bean单例池,缓存半成品的对象,且当前对象已经引用了;

三级缓存:单例Bean的工厂池,缓存半成品对象,对象未被引用,使用时在通过工厂创建Bean。

举例:

 

处理流程如下:

1.UserService实例化对象,但尚未初始化,将UserService存储到三级缓存;

2.开始UserService属性注入,发现UserDao需要,从缓存中获取,发现没有UserDao;

3.Spring开始对UserDao实例化对象,但尚未初始化,存放在三级缓存;

4.UserDao属性注入,需要UserService,从三级缓存中找UserService,并获取UserService,将UserService从三级缓存 移入二级缓存;

5.UserDao执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二级缓存;

6.UserService注入UserDao;

7.UserService执行其他生命周期过程,最终成为一个完成Bean,存储到一级缓存,删除二三级缓存。

具体项目:

两个实体类

package com.ly.pojo;


public class Student {
    public Student() {
        System.out.println("执行Student无参");
    }
}
package com.ly.pojo;


public class Teacher {
    private String msg;
    private Student student;

    public void setMsg(String msg) {
        this.msg = msg;
        System.out.println("执行Teacher属性赋值");
    }

    public void setStudent(Student student) {
        this.student = student;
        System.out.println("执行Teacher属性赋值");
    }

    public Teacher() {
        System.out.println("执行Teacher无参");
    }
}

 测试一:

配置文件

<?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 id="teacher" class="com.ly.pojo.Teacher">
        <property name="msg"  value="bbb"></property>
        <property name="student" ref="student"></property>
    </bean>
    <bean class="com.ly.pojo.Student" id="student"></bean>
</beans>
package com.ly.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Test1 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationConText.xml");
        Object teacher = applicationContext.getBean("teacher");
        System.out.println(teacher);
    }
}

 测试结果

测试二:

配置文件:

<?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  id="student" class="com.ly.pojo.Student"></bean>
    <bean id="teacher" class="com.ly.pojo.Teacher">
        <property name="msg" value="aaa"></property>
        <property name="student" ref="student"></property>
     </bean>
</beans>
package com.ly.test;

import org.springframework.context.support.ClassPathXmlApplicationContext;


public class Test1 {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationConText.xml");
        Object student = applicationContext.getBean("student");
        System.out.println(student);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值