spring中的相互引用问题

IOC指spring来创建对象实例,而不是Java代码中来做。

DI指spring根据对象的关系来注入相互之间的关系。

DI会引起相互引用的问题,即两个对象相互引用、相互依赖,类似于死锁的问题导致系统无法完成实例化。

报错如下:

Caused by: org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name ‘myBoss2‘: Requested bean is currently in creation: Is there an unresolvable circular reference?
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.beforeSingletonCreation(DefaultSingletonBeanRegistry.java:347)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
	... 61 more

解决办法是,不适用构造器注入,使用属性注入方式即可。其原理是属性注入方式是,先创建对象再去给对象的属性赋值。

代码如下:

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 id="myBoss1" class="beans.Boss">
        <property name="age" value="10"/>
        <property name="male" value="false"/>
        <property name="name" value="zhouhui"/>
        <!-- 引用car实例 -->
        <property name="car" ref="myCar1"/>
    </bean>

    <bean id="myCar1" class="beans.Car">
        <property name="brand" value="audi"/>
        <property name="price" value="10"/>
        <!-- 引用boss对象 -->
        <property name="boss" ref="myBoss1"/>
    </bean>

    <!-- 通过构造器注入方式的相互引用 -->
    <bean id="myBoss2" class="beans.Boss">
        <constructor-arg name="age" value="10"/>
        <constructor-arg name="isMale" value="true"/>
        <constructor-arg name="name" value="zhang"/>
        <!-- 引用car实例 -->
        <constructor-arg name="car" ref="myCar2"/>
    </bean>

    <bean id="myCar2" class="beans.Car">
        <constructor-arg name="brand" value="benz"/>
        <constructor-arg name="price" value="100"/>
        <!-- 引用boss对象 -->
        <constructor-arg name="boss" ref="myBoss2"/>
    </bean>

</beans>

java代码:

@Test
public void testLoop(){
    System.out.println("===========testLoop======================");
    System.out.println(myCar1);
    System.out.println(myBoss1);
    System.out.println(myBoss2);
    System.out.println(myCar2);
    System.out.println("===========testLoop======================");
}

其中 myCar1 myBoss1是能正常执行的,加上myBoss2 myCar2之后就会报错。

需要特别注意的是,如果bean都是单例的,spring容易会缓存实例,属性注入的相互引用没有问题。不过如果是多例的bean,相互引用及时是属性注入方式,还是会报错。

<!-- 通过属性注入方式的相互引用 -->
<bean id="myBoss3" class="beans.Boss" scope="prototype">
    <property name="age" value="10"/>
    <property name="male" value="false"/>
    <property name="name" value="zhouhui"/>
    <!-- 引用car实例 -->
    <property name="car" ref="myCar3"/>
</bean>

<bean id="myCar3" class="beans.Car" scope="prototype">
    <property name="brand" value="audi"/>
    <property name="price" value="10"/>
    <!-- 引用boss对象 -->
    <property name="boss" ref="myBoss3"/>
</bean>

scope="prototype" 意思是 每次请求都会创建一个实例对象。两者的区别是:有状态的bean都使用Prototype作用域,无状态的一般都使用singleton单例作用域。

对于“prototype”作用域Bean,Spring容器无法完成依赖注入,因为“prototype”作用域的Bean,Spring容
器不进行缓存,因此无法提前暴露一个创建中的Bean。

时间: 2024-11-08 17:55:19

spring中的相互引用问题的相关文章

Vue-Router路由Vue-CLI脚手架和模块化开发 之 在单文件组件项目中定义数据、方法和组件之间的相互引用

定义数据 根据上一篇博文配置项目的结构的基础上继续进行优化: 在app.vue中的导出模块/组件部分设置其属性: export default{//导出模块/组件 data(){ return{ name:'perfect', count:0 } }, 在一个template标签中进行调用: <template> <div> <h2> 欢迎来到perfect*的博客园!!!</h2> <h3>{{name}}</h3> </te

Spring中基于Java的容器配置(二)

使用@Configuration注解 @Configuration注解是一个类级别的注解,表明该对象是用来指定Bean的定义的.@Configuration注解的类通过@Bean注解的方法来声明Bean.通过调用注解了@Bean方法的返回的Bean可以用来构建Bean之间的相互依赖关系,可以通过前文来了解其基本概念. 注入inter-bean依赖 当@Bean方法依赖于其他的Bean的时候,可以通过在另一个方法中调用即可. @Configuration public class AppConfi

深入分析JavaWeb Item54 -- Spring中的AOP面向切面编程2

一.在Advice方法中获取目标方法的参数 1.获取目标方法的信息 访问目标方法最简单的做法是定义增强处理方法时,将第一个参数定义为JoinPoint类型,当该增强处理方法被调用时,该JoinPoint参数就代表了织入增强处理的连接点.JoinPoint里包含了如下几个常用的方法: Object[] getArgs:返回目标方法的参数 Signature getSignature:返回目标方法的签名 Object getTarget:返回被织入增强处理的目标对象 Object getThis:返

Spring中如何混用XML与Java装配方式

由David发表在天码营 多种装配方式的混用 除了自动配置,Spring使用显式的Java配置或者XML配置也可以完成任何装配.通常情况下可能在一个Spring项目中同时使用自动配置和显式配置. 对于自动配置,它自动从整个容器上下文中查找合适的bean,这个bean是通过@Component之类的标准,可能来自Java配置或者XML配置. 我们先来了解一下Java配置吧. Java配置 创建配置类 使用Java配置,通过创建一个专门用于Spring配置的类,然后通过@Configuration标

Spring 中的 Bean 配置

内容提要 •IOC & DI 概述 •配置 bean –配置形式:基于 XML 文件的方式:基于注解的方式 –Bean 的配置方式:通过全类名(反射).通过工厂方法(静态工厂方法 & 实例工厂方法).FactoryBean –IOC 容器 BeanFactory & ApplicationContext 概述 –依赖注入的方式:属性注入:构造器注入 –注入属性值细节 –自动转配 –bean 之间的关系:继承:依赖 –bean 的作用域:singleton:prototype:WEB

Spring笔记2——Spring中Bean的装配

1.引言 Spring中,对象无需自己负责查找或创建与其关联的其他对象,而是由容器负责把需要相互协作的对象引用赋予各个对象.创建应用对象之间的协作关系的行为通常称为装配(Wiring),这也是依赖注入的本质. 2.声明Bean 配置Bean的方式主要有两种:基于XML文件的配置方式和基于Java注解的配置方式.传统的基于XML文件的配置方式在声明Bean时,Spring配置文件的根元素来源于Spring beans命名空间所定义的<beans>元素.除了beans命名空间外,Java自带了多种

《Java从入门到放弃》入门篇:spring中IOC的注入姿势

IOC到底是个什么东东呢?控制反转(Inversion of Control,英文缩写为IoC),其实就是这个东东. 你随便百度一下就会得到比较书面的解释:通过引入实现了IoC模式的IoC容器,即可由IoC容器来管理对象的生命周期.依赖关系等,从而使得应用程序的配置和依赖性规范与实际的应用程序代码分开.其中一个特点就是通过文本的配置文件进行应用程序组件间相互关系的配置,而不用重新修改并编译具体的代码. 说了这么多,通过一个例子就能很好的来理解.以前小王要找对象,要么云茫茫人海中进行匹配(通过 小

spring中Bean的注入类型

1.属性注入    即通过setXxx()方法注入Bean的属性值或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,因此属性注入是实际应用中最常采用的注入方式.    属性注入要求Bean提供一个默认的构造参数,并为需要注入的属性提供对应的Setter方法.Spring先调用Bean的默认构造参数实例化Bean对象,然后通过反射的方式调用Setter方法注入属性值.    需要指出的是:Spring只会检查Bean中是否有对应的Setter方法,至于Bean中是否有对应的属性变量则不做要

Spring中父子容器的实现实例

Spring中父子容器的实现实例Spring的父子容器可以通过ConfigurableApplicationContext或ConfigurableBeanFactory来实现,这两个接口中分别有setParent及setParentBeanFactory方法,可以与当前的子容器进行父子容器关联,这个时候子容器就可以引用父容器中的bean,但是父容器是不能够引用子容器中的bean的,并且各个子容器中定义的bean是互不可见的,这样也可以避免因为不同的插件定义了相同的bean而带来的麻烦.应用场景