Spring之解决Bean间循环依赖

Spring通过DI(依赖注入)实现IOC(控制反转)

实例Bean注入

1、构造方法注入:

a) xml文件配置

b) java代码

public class UserService implements IUserService {

private IUserDao userDao;

public UserService(IUserDao userDao) {
    this.userDao = userDao;
}

public void loginUser() {
    userDao.loginUser();
}

}

注:
单个注入参数场景:
1、其中必须保证,com.lyu.spring.dao.impl.UserDaoJdbc 实现IUserDao接口

2、只有一个有参数的构造方法并且参数类型与注入的bean的类型匹配,那就会注入到该构造方法中。

3、如果有多个参数的构造方法,且都有要注入的参数类型。只会注入到只有一个参数的构造方法中,且与构造方法的顺序无关;如果没有单独一个的,会注入失败。

多个注入参数场景:

1、直接在xml配置多个construct-arg节点即可。

2、如果有多个构造方法,方法注入参数顺序不同时,跟顺序有关系,哪个在前会使用哪个构造方法。

2、Setter注入

xml配置文件:

注:spring会将name值的每个单词首字母转换成大写,然后再在前面拼接上”set”构成一个方法名,然后去对应的类中查找该方法,通过反射调用,实现注入。

切记:name属性值与类中的成员变量名以及set方法的参数名都无关,只与对应的set方法名有关,下面的这种写法是可以运行成功的

public class UserService implements IUserService {

private IUserDao userDao1;

public void setUserDao(IUserDao userDao1) {
    this.userDao1 = userDao1;
}

public void loginUser() {
    userDao1.loginUser();
}

}
还有一点需要注意:如果通过set方法注入属性,那么spring会通过默认的空参构造方法来实例化对象,所以如果在类中写了一个带有参数的构造方法,一定要把空参数的构造方法写上,否则spring没有办法实例化对象,导致报错。

3、基于注解方式

依赖关系注入

@Resource:
java的注解,默认以byName的方式去匹配与属性名相同的bean的id,如果没有找到就会以byType的方式查找,如果byType查找到多个的话,使用@Qualifier注解(spring注解)指定某个具体名称的bean。

@Autowired
java的注解,默认以byType的方式去匹配与属性名相同的bean的id,如果没有找到,再以byname方式匹配与属性名相同的bean的id。

Bean 循环依赖

1、构造方法的依赖

现象:Bean A引用Bean B,Bean B引用Bean C,Bean C引用Bean A。在创建A时,需要创建B,依次类推,三者形成一个环,形成循环依赖。

结果:Spring 在此场景下会抛出BeanCurrentlyInCreateException。

原理:Spring 在创建Bean时会维护一个"正在创建的Bean池",一旦有Bean的ID在池子里,如果在create该bean则会抛出上述异常。如果Bean被创建成功后,Bean会被移出"正在创建的池"

实例:

public class C {
private A a;

public C(){}
public C(A a){ this.a = a; }

public A getA() { return a; }
public void setA(A a) { this.a = a; }

public void hello(){ a.doHello(); }

public void doHello(){
    System.out.println("I am C");
}

}
A和B类结果类似C

main方法:

public class SpringMain {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext(“bean-circle.xml”);
A a = A.class.cast(ac.getBean(“a”));
a.hello();
}
}

调用main方法抛出异常。

原理:

Spring中不能存在构造方法中的循环引用,因为,还没创建要注入的属性值,无法赋值

2、Setter注入循环依赖

a) Spring 可以完成Bean在单例模式下的循环依赖,不会抛出异常。

原理:在一个单例bean创建的时候,Spring就把它当作存在循环依赖来处理,就是
1、在一个bean调用无参构造方法实例化结束之后,会放到三级缓存中提前曝光,让其他的依赖他的bean可以获得到还没有创建完成的它。
2、当在填充属性的时候如果发现有一个需要注入的属性值是一个引用值,在类型转换的时候就会在IOC容器中查找这个引用的bean,没有就先创建它,就这样一直递归着执行下去。
3、由于是循环依赖,就不可能有任何一个bean可以直接创建完,所以只能先把还没有填充属性的bean的引用赋给当前bean,Spring很巧妙的用了三级缓存来保留住了这个引用
4、从这也可以看出,Spring中不能存在构造方法中的循环引用,因为,还没创建要注入的属性值,无法赋值。
————————————————
版权声明:本文为CSDN博主「赵银龙」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_37343985/article/details/82822990

b) Spring无法完成Bean在非单例模式下的循环依赖,会抛出异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架采用依赖注入(DI)的方式来管理Bean,这种方式会解决Bean之循环依赖问题。在Spring容器启动时,它会先创建所有的Bean的实例,但是并不会对所有的依赖关系进行完全的填充,而是在构建Bean实例的过程中动态地解决依赖关系,从而避免了循环依赖的问题。 当需要创建一个Bean时,会经过以下步骤: 1. 创建Bean实例:当需要创建一个Bean时,Spring会将其实例化,并创建相应的BeanDefinition对象,以描述Bean的属性、依赖关系等。 2. 填充Bean属性:在Bean实例创建后,Spring会将Bean的属性值注入到Bean实例中。如果某些属性需要其他Bean的引用作为依赖,则Spring会用一个叫做代理的对象替代这些属性,这样就避免了循环依赖。 3. 调用初始化方法:在Bean实例化和属性填充后,Spring会调用Bean的初始化方法(如果有的话)。 对于循环依赖的情况,Spring会在填充属性时采用一些特殊的机制来处理。比如,当第一个Bean需要引用第二个Bean实例时,Spring会先创建一个半成品的Bean实例,然后注入到第一个Bean中。当第一个Bean创建完成后,会将其作为参数传递给第二个Bean的构造函数或者setter方法,以完成第二个Bean的创建。这样,就避免了两个Bean之循环依赖问题。 综上所述,Spring框架解决Bean的循环依赖问题的核心思想就是“先创建出半成品的Bean实例,然后在后续的构造器或setter方法中完成Beans之的注入和填充”。这种方式可以解决循环依赖问题,同时也保证了Bean之的正确依赖关系。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值