当前位置: 代码网 > it编程>编程语言>Java > Spring解决循环依赖问题的四种方法汇总

Spring解决循环依赖问题的四种方法汇总

2024年07月21日 Java 我要评论
spring解决循环依赖问题的四种方法@lazy方式使用setter/field injection使用@postconstruct实现 applicationcontextaware 和 initi

spring解决循环依赖问题的四种方法

  • @lazy方式
  • 使用setter/field injection
  • 使用@postconstruct
  • 实现 applicationcontextaware 和 initializingbean

不管使用那种方式,最佳的还是通过调整代码结构,从根上设计从而达到避免。

定义两个相互依赖的 bean(通过构造函数注入)

package icu.kevin.springpart.circular.constructor;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
@component
public class circulardependencya {
    private circulardependencyb circb;
    @autowired
    public circulardependencya(circulardependencyb circb) {
        this.circb = circb;
    }
}
package icu.kevin.springpart.circular.constructor;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
@component
public class circulardependencyb {
    private circulardependencya circa;
    @autowired
    public circulardependencyb(circulardependencya circa) {
        this.circa = circa;
    }
}
package icu.kevin.springpart.circular.constructor;
import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
@configuration
@componentscan(basepackages = { "icu.kevin.springpart.circular.constructor" })
public class testconfig {
}

编写测试用例,测试是否存在循环依赖

package icu.kevin.springpart.circular.constructor;
import org.junit.test;
import org.junit.runner.runwith;
import org.springframework.test.context.contextconfiguration;
import org.springframework.test.context.junit4.springjunit4classrunner;
@runwith(springjunit4classrunner.class)
@contextconfiguration(classes = { testconfig.class })
public class circulardependencyintegrationtest {
    // error creating bean with name 'circulardependencya': requested bean is currently in creation: is there an unresolvable circular reference?
    @test
    public void givencirculardependency_whenconstructorinjection_thenitfails() {
        // 测试可以为空,因为在上下文加载期间将检测到循环依赖关系
    }
}

@lazy方式

@lazy告诉 spring 延迟初始化其中一个 bean。因此,它不会完全初始化 bean,而是创建一个代理将其注入另一个 bean。注入的 bean 只有在第一次需要时才会完全创建。

@lazy 注解是通过建立一个中间代理层,来破解循环依赖的。

package icu.kevin.springpart.circular.lazy;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.annotation.lazy;
import org.springframework.stereotype.component;
@component
public class circulardependencya {
    private circulardependencyb circb;
    @autowired
    public circulardependencya(@lazy circulardependencyb circb) {
        this.circb = circb;
    }
}
package icu.kevin.springpart.circular.lazy;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
@component
public class circulardependencyb {
    private circulardependencya circa;
    @autowired
    public circulardependencyb(circulardependencya circa) {
        this.circa = circa;
    }
}
package icu.kevin.springpart.circular.lazy;
import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
@configuration
@componentscan(basepackages = { "icu.kevin.springpart.circular.lazy" })
public class testconfig {
}
package icu.kevin.springpart.circular.lazy;
import org.junit.test;
import org.junit.runner.runwith;
import org.springframework.test.context.contextconfiguration;
import org.springframework.test.context.junit4.springjunit4classrunner;
@runwith(springjunit4classrunner.class)
@contextconfiguration(classes = { testconfig.class })
public class circulardependencyintegrationtest {
    // error creating bean with name 'circulardependencya': requested bean is currently in creation: is there an unresolvable circular reference?
    @test
    public void givencirculardependency_whenconstructorinjection_thenitfails() {
        // 测试可以为空,因为在上下文加载期间将检测到循环依赖关系
    }
}

启动可以看出,在上下文检查循环依赖是可以正常通过的

查看源码contextannotationautowirecandidateresolver#getlazyresolutionproxyifnecessary首先会调用 islazy 去判断一下是否需要延迟加载,
如果需要,则调用 buildlazyresolutionproxy 方法构建一个延迟加载的对象;

使用setter/field injection

在setter注入的时候发生的依赖循环是可以被解决的,但只能解决单例情况的循环依赖。
对于setter注入造成的依赖是通过spring容器提前暴露刚刚完成构造器但还没有进行注入的bean来完成的。通过提前暴露一个单例工厂让其他的bean可以引用到该bean。

package icu.kevin.springpart.circular.setter;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
@component
public class circulardependencya {
    private circulardependencyb circb;
    public circulardependencyb getcircb() {
        return circb;
    }
    @autowired
    public void setcircb(circulardependencyb circb) {
        this.circb = circb;
    }
}
package icu.kevin.springpart.circular.setter;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
@component
public class circulardependencyb {
    private circulardependencya circa;
    private string message = "hi!";
    public circulardependencya getcirca() {
        return circa;
    }
    @autowired
    public void setcirca(circulardependencya circa) {
        this.circa = circa;
    }
    public string getmessage() {
        return message;
    }
    public void setmessage(string message) {
        this.message = message;
    }
}
package icu.kevin.springpart.circular.setter;
import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
@configuration
@componentscan(basepackages = { "icu.kevin.springpart.circular.setter" })
public class testconfig {
}
package icu.kevin.springpart.circular.setter;
import org.junit.assert;
import org.junit.test;
import org.junit.runner.runwith;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.applicationcontext;
import org.springframework.test.context.contextconfiguration;
import org.springframework.test.context.junit4.springjunit4classrunner;
@runwith(springjunit4classrunner.class)
@contextconfiguration(classes = { testconfig.class })
public class circulardependencyintegrationtest {
    @autowired
    private applicationcontext context;
    @test
    public void givencirculardependency_whenconstructorinjection_thenitfails() {
        // empty test; we just want the context to load
        circulardependencya circa = context.getbean(circulardependencya.class);
        assert.assertequals("hi!", circa.getcircb().getmessage());
    }
}

使用@postconstruct

package icu.kevin.springpart.circular.postconstruct;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.stereotype.component;
import javax.annotation.postconstruct;
@component
public class circulardependencya {
    @autowired
    private circulardependencyb circb;
    @postconstruct
    public void init(){
        circb.setcirca(this);
    }
    public circulardependencyb getcircb() {
        return circb;
    }
}
package icu.kevin.springpart.circular.postconstruct;
import org.springframework.stereotype.component;
@component
public class circulardependencyb {
    private circulardependencya circa;
    private string message = "hi!";
    public circulardependencya getcirca() {
        return circa;
    }
    public void setcirca(circulardependencya circa) {
        this.circa = circa;
    }
    public string getmessage() {
        return message;
    }
    public void setmessage(string message) {
        this.message = message;
    }
}
package icu.kevin.springpart.circular.postconstruct;
import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
@configuration
@componentscan(basepackages = { "icu.kevin.springpart.circular.postconstruct" })
public class testconfig {
}
package icu.kevin.springpart.circular.postconstruct;
import org.junit.assert;
import org.junit.test;
import org.junit.runner.runwith;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.applicationcontext;
import org.springframework.test.context.contextconfiguration;
import org.springframework.test.context.junit4.springjunit4classrunner;
@runwith(springjunit4classrunner.class)
@contextconfiguration(classes = { testconfig.class })
public class circulardependencyintegrationtest {
    @autowired
    private applicationcontext context;
    @test
    public void givencirculardependency_whenconstructorinjection_thenitfails() {
        //
        circulardependencya circa = context.getbean(circulardependencya.class);
        assert.assertequals("hi!", circa.getcircb().getmessage());
    }
}

实现 applicationcontextaware 和 initializingbean

如果其中一个 bean 实现了 applicationcontextaware,则该 bean 可以访问 spring 上下文,并可以从那里提取另一个 bean。

通过实现 initializingbean,我们指示该 bean 在设置完所有属性后必须执行一些操作。在这种情况下,我们要手动设置依赖项。

package icu.kevin.springpart.circular.initializingbean;
import org.springframework.beans.beansexception;
import org.springframework.beans.factory.initializingbean;
import org.springframework.context.applicationcontext;
import org.springframework.context.applicationcontextaware;
import org.springframework.stereotype.component;
@component
public class circulardependencya implements applicationcontextaware, initializingbean {
    private circulardependencyb circb;
    private applicationcontext context;
    public circulardependencyb getcircb() {
        return circb;
    }
    @override
    public void afterpropertiesset() throws exception {
        circb = context.getbean(circulardependencyb.class);
    }
    @override
    public void setapplicationcontext(final applicationcontext ctx) throws beansexception {
        context = ctx;
    }
}
package icu.kevin.springpart.circular.initializingbean;
import org.springframework.stereotype.component;
@component
public class circulardependencyb {
    private circulardependencya circa;
    private string message = "hi!";
    public circulardependencya getcirca() {
        return circa;
    }
    public void setcirca(circulardependencya circa) {
        this.circa = circa;
    }
    public string getmessage() {
        return message;
    }
    public void setmessage(string message) {
        this.message = message;
    }
}
package icu.kevin.springpart.circular.initializingbean;
import org.springframework.context.annotation.componentscan;
import org.springframework.context.annotation.configuration;
@configuration
@componentscan(basepackages = { "icu.kevin.springpart.circular.initializingbean" })
public class testconfig {
}
package icu.kevin.springpart.circular.initializingbean;
import org.junit.assert;
import org.junit.test;
import org.junit.runner.runwith;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.context.applicationcontext;
import org.springframework.test.context.contextconfiguration;
import org.springframework.test.context.junit4.springjunit4classrunner;
@runwith(springjunit4classrunner.class)
@contextconfiguration(classes = { testconfig.class })
public class circulardependencyintegrationtest {
    @autowired
    private applicationcontext context;
    @test
    public void givencirculardependency_whenconstructorinjection_thenitfails() {
        // empty test; we just want the context to load
        circulardependencya circa = context.getbean(circulardependencya.class);
        assert.assertequals("hi!", circa.getcircb().getmessage());
    }
}

到此这篇关于spring解决循环依赖问题的四种方法的文章就介绍到这了,更多相关spring循环依赖内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com