相互注入引发的StackOverflowError

本文记录了一次在Spring框架中因循环依赖导致StackOverflowError的案例,详细解析了错误发生的原因及解决过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

平时工作StackOverflowError是很少出现的,今天写一个demo出现了,记录一下,应该算是一个典型的StackOverflowError。

[DEBUG] 2018-08-08 14:52:19,159 method:org.springframework.beans.factory.xml.PluggableSchemaResolver.resolveEntity(PluggableSchemaResolver.java:119)
Found XML schema [http://www.springframework.org/schema/beans/spring-beans.xsd] in classpath: org/springframework/beans/factory/xml/spring-beans-4.3.xsd
[DEBUG] 2018-08-08 14:52:19,278 method:org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:92)
Loading bean definitions
[DEBUG] 2018-08-08 14:52:19,329 method:org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:224)
Loaded 5 bean definitions from location pattern [spring.xml]
[DEBUG] 2018-08-08 14:52:19,330 method:org.springframework.context.support.AbstractApplicationContext.obtainFreshBeanFactory(AbstractApplicationContext.java:617)
Bean factory for org.springframework.context.support.ClassPathXmlApplicationContext@32d2fa64: org.springframework.beans.factory.support.DefaultListableBeanFactory@1b2abca6: defining beans [stu,stu2,stu3,stu4,classes]; root of factory hierarchy
[DEBUG] 2018-08-08 14:52:19,507 method:org.springframework.context.support.AbstractApplicationContext.initMessageSource(AbstractApplicationContext.java:734)
Unable to locate MessageSource with name 'messageSource': using default [org.springframework.context.support.DelegatingMessageSource@5d0bf09b]
[DEBUG] 2018-08-08 14:52:19,548 method:org.springframework.context.support.AbstractApplicationContext.initApplicationEventMulticaster(AbstractApplicationContext.java:758)
Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster': using default [org.springframework.context.event.SimpleApplicationEventMulticaster@6bbe85a8]
[DEBUG] 2018-08-08 14:52:19,551 method:org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:730)
Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1b2abca6: defining beans [stu,stu2,stu3,stu4,classes]; root of factory hierarchy
[DEBUG] 2018-08-08 14:52:19,613 method:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
Creating shared instance of singleton bean 'stu'
[DEBUG] 2018-08-08 14:52:19,614 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:449)
Creating instance of bean 'stu'
[DEBUG] 2018-08-08 14:52:19,688 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
Eagerly caching bean 'stu' to allow for resolving potential circular references
[DEBUG] 2018-08-08 14:52:19,900 method:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
Creating shared instance of singleton bean 'classes'
[DEBUG] 2018-08-08 14:52:19,900 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:449)
Creating instance of bean 'classes'
[DEBUG] 2018-08-08 14:52:19,901 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
Eagerly caching bean 'classes' to allow for resolving potential circular references
[DEBUG] 2018-08-08 14:52:19,910 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:247)
Returning eagerly cached instance of singleton bean 'stu' that is not fully initialized yet - a consequence of a circular reference
[DEBUG] 2018-08-08 14:52:19,911 method:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
Creating shared instance of singleton bean 'stu2'
[DEBUG] 2018-08-08 14:52:19,911 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:449)
Creating instance of bean 'stu2'
[DEBUG] 2018-08-08 14:52:19,911 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
Eagerly caching bean 'stu2' to allow for resolving potential circular references
[DEBUG] 2018-08-08 14:52:19,916 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:485)
Finished creating instance of bean 'stu2'
[DEBUG] 2018-08-08 14:52:19,960 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:485)
Finished creating instance of bean 'classes'
[DEBUG] 2018-08-08 14:52:19,960 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:485)
Finished creating instance of bean 'stu'
[DEBUG] 2018-08-08 14:52:19,961 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251)
Returning cached instance of singleton bean 'stu2'
[DEBUG] 2018-08-08 14:52:19,961 method:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
Creating shared instance of singleton bean 'stu3'
[DEBUG] 2018-08-08 14:52:19,962 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:449)
Creating instance of bean 'stu3'
[DEBUG] 2018-08-08 14:52:20,014 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
Eagerly caching bean 'stu3' to allow for resolving potential circular references
[DEBUG] 2018-08-08 14:52:20,015 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:485)
Finished creating instance of bean 'stu3'
[DEBUG] 2018-08-08 14:52:20,016 method:org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:221)
Creating shared instance of singleton bean 'stu4'
[DEBUG] 2018-08-08 14:52:20,017 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:449)
Creating instance of bean 'stu4'
[DEBUG] 2018-08-08 14:52:20,019 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
Eagerly caching bean 'stu4' to allow for resolving potential circular references
[DEBUG] 2018-08-08 14:52:20,020 method:org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:485)
Finished creating instance of bean 'stu4'
[DEBUG] 2018-08-08 14:52:20,022 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251)
Returning cached instance of singleton bean 'classes'
[DEBUG] 2018-08-08 14:52:20,028 method:org.springframework.context.support.AbstractApplicationContext.initLifecycleProcessor(AbstractApplicationContext.java:785)
Unable to locate LifecycleProcessor with name 'lifecycleProcessor': using default [org.springframework.context.support.DefaultLifecycleProcessor@63eef88a]
[DEBUG] 2018-08-08 14:52:20,030 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251)
Returning cached instance of singleton bean 'lifecycleProcessor'
[DEBUG] 2018-08-08 14:52:20,044 method:org.springframework.core.env.PropertySourcesPropertyResolver.getProperty(PropertySourcesPropertyResolver.java:92)
Could not find key 'spring.liveBeansView.mbeanDomain' in any property source
[DEBUG] 2018-08-08 14:52:20,047 method:org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:251)
Returning cached instance of singleton bean 'classes'
Exception in thread "main" java.lang.StackOverflowError
	at java.lang.StringBuilder.append(StringBuilder.java:136)
	at com.jiangcheng.entity.Student.toString(Student.java:15)
	at java.lang.String.valueOf(String.java:2994)
	at java.lang.StringBuilder.append(StringBuilder.java:131)
	at java.util.AbstractCollection.toString(AbstractCollection.java:462)
	at java.lang.String.valueOf(String.java:2994)
	...
	at java.lang.StringBuilder.append(StringBuilder.java:131)
	at java.util.AbstractCollection.toString(AbstractCollection.java:462)
	at java.lang.String.valueOf(String.java:2994)
	at java.lang.StringBuilder.append(StringBuilder.java:131)
Disconnected from the target VM, address: '127.0.0.1:55210', transport: 'socket'

Process finished with exit code 1

从日志可以看出这次StackOverflowError是由于相互调用无限循环造成的,代码如下:

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">

    <!--配置student对象-->

    <!--<bean id="stu" class="com.jiangcheng.entity.Student"></bean>--><!--v1 打印之后没有初始化值-->
    <bean id="stu" class="com.jiangcheng.entity.Student">
        <property name="id" value="1"></property>
        <property name="name">
            <value><![CDATA[<张三>]]></value>
        </property>
        <property name="age" value="23"></property>
        <!-- 将classes对象赋给stu对象 -->
        <property name="classes" ref="classes"></property>
    </bean>

    <bean id="stu2" class="com.jiangcheng.entity.Student">
        <property name="id" value="1"></property>
        <property name="name" value="李四"></property>
        <property name="age" value="23"></property>
    </bean>

    <!-- 通过有参构造函数创建对象 -->
    <bean id="stu3" class="com.jiangcheng.entity.Student">
        <constructor-arg name="id" value="3"></constructor-arg>
        <constructor-arg name="name" value="小明"></constructor-arg>
        <constructor-arg name="age" value="22"></constructor-arg>
    </bean>

    <bean id="stu4" class="com.jiangcheng.entity.Student">
        <constructor-arg index="0" value="4"></constructor-arg>
        <constructor-arg index="1" value="小明"></constructor-arg>
        <constructor-arg index="2" value="22"></constructor-arg>
    </bean>

    <!--创建classes对象-->
    <bean id="classes" class="com.jiangcheng.entity.Classes">
        <property name="id" value="1"></property>
        <property name="name" value="Java"></property>
        <property name="students">
            <!-- 注入student对象 -->
            <list>
                <ref bean="stu2"/>
                <ref bean="stu3"/>
            </list>
        </property>
    </bean>

</beans>

Student.java

package com.jiangcheng.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * 类名称:Student<br>
 * 类描述:<br>
 * 创建时间:2018年08月08日<br>
 *
 * @author jiangcheng
 * @version 1.0.0
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private int id;
    private String name;
    private int age;
    private Classes classes;
    public Student(int id,String name,int age){
        this.id = id;
        this.name = name;
        this.age = age;
    }
}

Classes.java

package com.jiangcheng.entity;

import lombok.Data;

import java.util.List;

/**
 * 类名称:Classes<br>
 * 类描述:<br>
 * 创建时间:2018年08月08日<br>
 *
 * @author jiangcheng
 * @version 1.0.0
 */
@Data
public class Classes {
    private int id;
    private String name;
    private List<Student> students;
}

StudentTest.java

package com.jiangcheng.entity;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import static org.junit.Assert.*;

/**
 * 类名称:StudentTest<br>
 * 类描述:<br>
 * 创建时间:2018年08月08日<br>
 *
 * @author jiangcheng
 * @version 1.0.0
 */
public class StudentTest {

    public static void main(String[] args) {
        //Student student = new Student();
        //System.out.println(student);

        //1.加载spring.xml配置文件
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.通过id获取值对象
        //Student stu = applicationContext.getBean(Student.class);//No qualifying bean of type 'com.jiangcheng.entity.Student' available: expected single matching bean but found 2: stu,stu2
        //Student stu = (Student) applicationContext.getBean("stu");///Student(id=1, name=<张三>, age=23)
        //Student stu = (Student) applicationContext.getBean("stu3");///Student(id=1, name=<张三>, age=23)
        //Student stu = (Student) applicationContext.getBean("stu4");///Student(id=1, name=<张三>, age=23)
        Classes classes = (Classes) applicationContext.getBean("classes");
        System.out.println(classes);
    }
}

解决方案,修改依赖关系,spring.xml中对classes对象的ref进行稍稍改变,去掉stu引用

<!--创建classes对象-->
    <bean id="classes" class="com.jiangcheng.entity.Classes">
        <property name="id" value="1"></property>
        <property name="name" value="Java"></property>
        <property name="students">
            <!-- 注入student对象 -->
            <list>
                <ref bean="stu2"/>
                <ref bean="stu3"/>
            </list>
        </property>
    </bean>

再次运行test,打印日志

Classes(id=1, name=Java, students=[Student(id=1, name=李四, age=23, classes=null), Student(id=3, name=小明, age=22, classes=null)])

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值