这篇文章是关于如何解决 Spring 中导致 UnsatisfiedDependencyException
的循环依赖问题。简而言之,当两个服务相互依赖时会导致循环依赖问题。
循环依赖是在依赖注入期间spring-context尝试加载对象并且一个bean依赖另一个bean时引起的问题。假设当对象 A 和 B 相互依赖时,即 A 依赖于 B,反之亦然。 Spring 在创建 A 和 B 的对象时抛出 UnsatisfiedDependencyException
,因为除非创建 B,否则无法创建 A 对象,反之亦然。
让我们使用真实的代码示例来理解它。创建两个服务 ServiceA
和 ServiceB
并尝试将 ServiceA
注入 ServiceB
,反之亦然,如上图所示。
ServiceA.java
package org.websparrow.service;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private ServiceB serviceB;
public ServiceA(ServiceB serviceB) {
System.out.println("Calling Service A");
this.serviceB = serviceB;
}
}
ServiceB.java
package org.websparrow.service;
import org.springframework.stereotype.Service;
@Service
public class ServiceB {
private ServiceA serviceA;
public ServiceB(ServiceA serviceA) {
System.out.println("Calling Service B");
this.serviceA = serviceA;
}
}
要模拟循环依赖问题,请运行以下类,并查看控制台日志。
CircularDependenciesTestApp.java
package org.websparrow;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class CircularDependenciesTestApp {
public static void main(String[] args) {
SpringApplication.run(CircularDependenciesTestApp.class, args);
}
}
当我们执行 CircularDependenciesTestApp
类时,由于相互之间的循环依赖,它将无法注入依赖项,并且会抛出一个 checked 异常,如下所示:
控制台日志
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-05-27 21:22:46.368 ERROR 4480 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| serviceA defined in file [F:\sts4-workspace\circular-dependencies-spring\target\classes\org\websparrow\service\ServiceA.class]
↑ ↓
| serviceB defined in file [F:\sts4-workspace\circular-dependencies-spring\target\classes\org\websparrow\service\ServiceB.class]
└─────┘
###如何解决这个问题?
要解决循环依赖问题,您有两种选择:
我们可以在构造函数注入期间延迟初始化 ServiceB
bean,以延迟构造 ServiceB
bean。为了更清晰,以下是 ServiceA
中的代码更改:
ServiceA.java
package org.websparrow.service;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private ServiceB serviceB;
public ServiceA(@Lazy ServiceB serviceB) {
System.out.println("Calling Service A");
this.serviceB = serviceB;
}
}
如果你再次运行 CircularDependenciesTestApp
类,你会发现循环依赖问题解决了。
控制台日志
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.0.RELEASE)
2020-05-27 21:33:22.637 INFO 7156 --- [ main] o.w.CircularDependenciesTestApp : Starting CircularDependenciesTestApp on Atul-PC with PID 7156 (F:\sts4-workspace\circular-dependencies-spring\target\classes started by Atul in F:\sts4-workspace\circular-dependencies-spring)
2020-05-27 21:33:22.640 INFO 7156 --- [ main] o.w.CircularDependenciesTestApp : No active profile set, falling back to default profiles: default
Calling Service A
Calling Service B
2020-05-27 21:33:23.251 INFO 7156 --- [ main] o.w.CircularDependenciesTestApp : Started CircularDependenciesTestApp in 0.98 seconds (JVM running for 1.667)
使用 @Autowired
和 @Lazy
注释将 ServiceB
注入 ServiceA
。让我们使用这些注解来注入 bean 并测试我们的应用程序是否解决了问题:
ServiceA.java
package org.websparrow.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
@Autowired
@Lazy
private ServiceB serviceB;
/*
public ServiceA(ServiceB serviceB) {
System.out.println("Calling Service A");
this.serviceB = serviceB;
}
*/
}
这是再次运行 CircularDependenciesTestApp
类时控制台日志上的输出:
控制台日志
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.3.0.RELEASE)
2020-05-27 21:45:07.583 INFO 4036 --- [ main] o.w.CircularDependenciesTestApp : Starting CircularDependenciesTestApp on Atul-PC with PID 4036 (F:\sts4-workspace\circular-dependencies-spring\target\classes started by Atul in F:\sts4-workspace\circular-dependencies-spring)
2020-05-27 21:45:07.586 INFO 4036 --- [ main] o.w.CircularDependenciesTestApp : No active profile set, falling back to default profiles: default
Calling Service B
2020-05-27 21:45:08.141 INFO 4036 --- [ main] o.w.CircularDependenciesTestApp : Started CircularDependenciesTestApp in 0.928 seconds (JVM running for 1.614)
在本教程中,我们了解了什么是循环依赖,它何时出现在应用程序中以及如何解决它。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://www.websparrow.org/spring/circular-dependencies-in-spring
内容来源于网络,如有侵权,请联系作者删除!