今天遇到一个很有意思的bug,当程序开发完成后打包到服务器运行,总是会出现栈溢出异常,经过排查发现,问题出现在一个接口上,但这个接口逻辑并不复杂,除了几局逻辑代码外和打印语句之外也没有其他的了,但是只要调用这个接口就马上会出现栈溢出的异常,随后对代码进行了排查,最后发现问题居然出现在日志打印语句上。

平常在开发过程中我们经过会通知打印日志来了解程序的运行状态,没想到今天在这上面翻了车,这个打印语句是打印一个对象,我们知道,当要打印一个对象的时候会自动调用对象的toString()方法,项目中我们会使用lombok插件来帮助我们生成对应的get、set、equals、hashcode、toString等方法,而打印的这个对象在由Spring容器管理的一个bean,我们给这个bean取名A,在A里面又依赖注入了另一个bean,我们取名B,A和B形成了循环依赖,且都重写了toString方法,所以当调用A的toString方法时,会调用B的toString方法,当调用B的toString又会调用A的toString,由此形成了死循环,最终导致了栈溢出的异常。 下面是我精简出的出现问题的代码结构,帮助大家避坑 类A结构

public class A {

    private B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    @Override
    public String toString() {
        return "A{" +
                "b=" + b +
                '}';
    }
}

类B结构

public class B {

    private A a;

    public A getA() {
        return a;
    }

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

    @Override
    public String toString() {
        return "B{" +
                "a=" + a +
                '}';
    }
}

Spring配置文件,类A类B交给容器管理

<bean id="a" class="com.zlm.bean.A">
    <property name="b" ref="b"/>
</bean>
<bean id="b" class="com.zlm.bean.B">
    <property name="a" ref="a"/>
</bean>

主程序

public class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext xmlApplicationContext = new ClassPathXmlApplicationContext("bean.xml");
        A bean = xmlApplicationContext.getBean(A.class);
        // 会报错
        System.out.println(bean);
    }
}

错误信息

Exception in thread "main" java.lang.StackOverflowError
BUG
作者:|Liming_Code|,原文链接: https://www.cnblogs.com/lm66/p/16301220.html

文章推荐

Golang 协程/线程/进程 区别以及 GMP 详解

java中this的内存原理以及成员变量和局部变量

docker安装jenkins

排序算法之详解冒泡排序

对dubbo的DubboReference.check的参数进行剖析

fork语句遇见for循环语句

Shifu高级功能:命令行中间件之HTTP 到 SSH 的中间件

GPT-4 来了!这些开源的 GPT 应用又要变强了

HTTP面试题 - HTTP2 面试题

栈溢出基础

CXP 协议中upconnection 与downconnection的说明及其区别

接口的幂等性如何设计?