Springboot 循环依赖
一、测试用例
package com.example.MySpringBootTest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
@Autowired
private ServiceB serviceB;
}
package com.example.MySpringBootTest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
启动后直接报错:
/Users/weiwei/Library/Java/JavaVirtualMachines/corretto-21.0.5/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=55878:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8 -classpath /Users/weiwei/Documents/MySpringBootTest/target/classes:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter/3.0.12/spring-boot-starter-3.0.12.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot/3.0.12/spring-boot-3.0.12.jar:/Users/weiwei/.m2/repository/org/springframework/spring-context/6.0.13/spring-context-6.0.13.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/3.0.12/spring-boot-autoconfigure-3.0.12.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter-logging/3.0.12/spring-boot-starter-logging-3.0.12.jar:/Users/weiwei/.m2/repository/ch/qos/logback/logback-classic/1.4.11/logback-classic-1.4.11.jar:/Users/weiwei/.m2/repository/ch/qos/logback/logback-core/1.4.11/logback-core-1.4.11.jar:/Users/weiwei/.m2/repository/org/apache/logging/log4j/log4j-to-slf4j/2.19.0/log4j-to-slf4j-2.19.0.jar:/Users/weiwei/.m2/repository/org/apache/logging/log4j/log4j-api/2.19.0/log4j-api-2.19.0.jar:/Users/weiwei/.m2/repository/org/slf4j/jul-to-slf4j/2.0.9/jul-to-slf4j-2.0.9.jar:/Users/weiwei/.m2/repository/jakarta/annotation/jakarta.annotation-api/2.1.1/jakarta.annotation-api-2.1.1.jar:/Users/weiwei/.m2/repository/org/springframework/spring-core/6.0.13/spring-core-6.0.13.jar:/Users/weiwei/.m2/repository/org/springframework/spring-jcl/6.0.13/spring-jcl-6.0.13.jar:/Users/weiwei/.m2/repository/org/yaml/snakeyaml/1.33/snakeyaml-1.33.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter-web/3.0.12/spring-boot-starter-web-3.0.12.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter-json/3.0.12/spring-boot-starter-json-3.0.12.jar:/Users/weiwei/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.14.3/jackson-databind-2.14.3.jar:/Users/weiwei/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.14.3/jackson-annotations-2.14.3.jar:/Users/weiwei/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.14.3/jackson-core-2.14.3.jar:/Users/weiwei/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.14.3/jackson-datatype-jdk8-2.14.3.jar:/Users/weiwei/.m2/repository/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.14.3/jackson-datatype-jsr310-2.14.3.jar:/Users/weiwei/.m2/repository/com/fasterxml/jackson/module/jackson-module-parameter-names/2.14.3/jackson-module-parameter-names-2.14.3.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter-tomcat/3.0.12/spring-boot-starter-tomcat-3.0.12.jar:/Users/weiwei/.m2/repository/org/apache/tomcat/embed/tomcat-embed-core/10.1.15/tomcat-embed-core-10.1.15.jar:/Users/weiwei/.m2/repository/org/apache/tomcat/embed/tomcat-embed-el/10.1.15/tomcat-embed-el-10.1.15.jar:/Users/weiwei/.m2/repository/org/apache/tomcat/embed/tomcat-embed-websocket/10.1.15/tomcat-embed-websocket-10.1.15.jar:/Users/weiwei/.m2/repository/org/springframework/spring-web/6.0.13/spring-web-6.0.13.jar:/Users/weiwei/.m2/repository/org/springframework/spring-beans/6.0.13/spring-beans-6.0.13.jar:/Users/weiwei/.m2/repository/org/springframework/spring-webmvc/6.0.13/spring-webmvc-6.0.13.jar:/Users/weiwei/.m2/repository/org/springframework/spring-expression/6.0.13/spring-expression-6.0.13.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter-aop/3.0.12/spring-boot-starter-aop-3.0.12.jar:/Users/weiwei/.m2/repository/org/springframework/spring-aop/6.0.13/spring-aop-6.0.13.jar:/Users/weiwei/.m2/repository/org/aspectj/aspectjweaver/1.9.20/aspectjweaver-1.9.20.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter-actuator/3.0.12/spring-boot-starter-actuator-3.0.12.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-actuator-autoconfigure/3.0.12/spring-boot-actuator-autoconfigure-3.0.12.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-actuator/3.0.12/spring-boot-actuator-3.0.12.jar:/Users/weiwei/.m2/repository/io/micrometer/micrometer-observation/1.10.12/micrometer-observation-1.10.12.jar:/Users/weiwei/.m2/repository/io/micrometer/micrometer-commons/1.10.12/micrometer-commons-1.10.12.jar:/Users/weiwei/.m2/repository/io/micrometer/micrometer-core/1.10.12/micrometer-core-1.10.12.jar:/Users/weiwei/.m2/repository/org/hdrhistogram/HdrHistogram/2.1.12/HdrHistogram-2.1.12.jar:/Users/weiwei/.m2/repository/org/latencyutils/LatencyUtils/2.0.3/LatencyUtils-2.0.3.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-spring-boot3/2.0.2/resilience4j-spring-boot3-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-spring6/2.0.2/resilience4j-spring6-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-annotations/2.0.2/resilience4j-annotations-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-consumer/2.0.2/resilience4j-consumer-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-core/2.0.2/resilience4j-core-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-circularbuffer/2.0.2/resilience4j-circularbuffer-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-framework-common/2.0.2/resilience4j-framework-common-2.0.2.jar:/Users/weiwei/.m2/repository/org/slf4j/slf4j-api/2.0.9/slf4j-api-2.0.9.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-micrometer/2.0.2/resilience4j-micrometer-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-bulkhead/2.0.2/resilience4j-bulkhead-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-circuitbreaker/2.0.2/resilience4j-circuitbreaker-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-retry/2.0.2/resilience4j-retry-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-ratelimiter/2.0.2/resilience4j-ratelimiter-2.0.2.jar:/Users/weiwei/.m2/repository/io/github/resilience4j/resilience4j-timelimiter/2.0.2/resilience4j-timelimiter-2.0.2.jar:/Users/weiwei/.m2/repository/com/google/guava/guava/31.1-jre/guava-31.1-jre.jar:/Users/weiwei/.m2/repository/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar:/Users/weiwei/.m2/repository/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:/Users/weiwei/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/weiwei/.m2/repository/org/checkerframework/checker-qual/3.12.0/checker-qual-3.12.0.jar:/Users/weiwei/.m2/repository/com/google/errorprone/error_prone_annotations/2.11.0/error_prone_annotations-2.11.0.jar:/Users/weiwei/.m2/repository/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar:/Users/weiwei/.m2/repository/com/baomidou/mybatis-plus-boot-starter/3.5.3.1/mybatis-plus-boot-starter-3.5.3.1.jar:/Users/weiwei/.m2/repository/com/baomidou/mybatis-plus/3.5.3.1/mybatis-plus-3.5.3.1.jar:/Users/weiwei/.m2/repository/com/baomidou/mybatis-plus-extension/3.5.3.1/mybatis-plus-extension-3.5.3.1.jar:/Users/weiwei/.m2/repository/com/baomidou/mybatis-plus-core/3.5.3.1/mybatis-plus-core-3.5.3.1.jar:/Users/weiwei/.m2/repository/com/baomidou/mybatis-plus-annotation/3.5.3.1/mybatis-plus-annotation-3.5.3.1.jar:/Users/weiwei/.m2/repository/com/github/jsqlparser/jsqlparser/4.4/jsqlparser-4.4.jar:/Users/weiwei/.m2/repository/org/mybatis/mybatis/3.5.10/mybatis-3.5.10.jar:/Users/weiwei/.m2/repository/org/mybatis/mybatis-spring/2.0.7/mybatis-spring-2.0.7.jar:/Users/weiwei/.m2/repository/org/springframework/boot/spring-boot-starter-jdbc/3.0.12/spring-boot-starter-jdbc-3.0.12.jar:/Users/weiwei/.m2/repository/com/zaxxer/HikariCP/5.0.1/HikariCP-5.0.1.jar:/Users/weiwei/.m2/repository/org/springframework/spring-jdbc/6.0.13/spring-jdbc-6.0.13.jar:/Users/weiwei/.m2/repository/org/springframework/spring-tx/6.0.13/spring-tx-6.0.13.jar:/Users/weiwei/.m2/repository/com/mysql/mysql-connector-j/8.1.0/mysql-connector-j-8.1.0.jar:/Users/weiwei/.m2/repository/com/baomidou/mybatis-plus-generator/3.5.3.1/mybatis-plus-generator-3.5.3.1.jar:/Users/weiwei/.m2/repository/org/freemarker/freemarker/2.3.31/freemarker-2.3.31.jar com.example.MySpringBootTest.MySpringBootTestApplication
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.0.12)
2025-03-04T15:42:40.983+08:00 INFO 51172 --- [ main] c.e.M.MySpringBootTestApplication : Starting MySpringBootTestApplication using Java 21.0.5 with PID 51172 (/Users/weiwei/Documents/MySpringBootTest/target/classes started by weiwei in /Users/weiwei/Documents/MySpringBootTest)
2025-03-04T15:42:40.985+08:00 INFO 51172 --- [ main] c.e.M.MySpringBootTestApplication : The following 1 profile is active: "dev"
2025-03-04T15:42:42.788+08:00 INFO 51172 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8081 (http)
2025-03-04T15:42:42.798+08:00 INFO 51172 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2025-03-04T15:42:42.798+08:00 INFO 51172 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.15]
2025-03-04T15:42:42.896+08:00 INFO 51172 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2025-03-04T15:42:42.897+08:00 INFO 51172 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 1868 ms
Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
Parsed mapper file: 'file [/Users/weiwei/Documents/MySpringBootTest/target/classes/mapper/UserMapper.xml]'
_ _ |_ _ _|_. ___ _ | _
| | |\/|_)(_| | |_\ |_)||_|_\
/ |
3.5.3.1
2025-03-04T15:42:43.848+08:00 WARN 51172 --- [ main] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'serviceA': Unsatisfied dependency expressed through field 'serviceB': Error creating bean with name 'serviceB': Unsatisfied dependency expressed through field 'serviceA': Error creating bean with name 'serviceA': Requested bean is currently in creation: Is there an unresolvable circular reference?
2025-03-04T15:42:43.852+08:00 INFO 51172 --- [ main] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2025-03-04T15:42:43.870+08:00 INFO 51172 --- [ main] .s.b.a.l.ConditionEvaluationReportLogger :
Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-03-04T15:42:43.892+08:00 ERROR 51172 --- [ 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 (field private com.example.MySpringBootTest.service.impl.ServiceB com.example.MySpringBootTest.service.impl.ServiceA.serviceB)
↑ ↓
| serviceB (field private com.example.MySpringBootTest.service.impl.ServiceA com.example.MySpringBootTest.service.impl.ServiceB.serviceA)
└─────┘
Action:
Relying upon circular references is discouraged and they are prohibited by default. Update your application to remove the dependency cycle between beans. As a last resort, it may be possible to break the cycle automatically by setting spring.main.allow-circular-references to true.
Process finished with exit code 1
二、解决方案
1 - 用Setter注入替换构造器注入
package com.example.MySpringBootTest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServiceA {
private ServiceB serviceB;
public void setServiceB(ServiceB serviceB) {
this.serviceB = serviceB;
}
}
package com.example.MySpringBootTest.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ServiceB {
private ServiceA serviceA;
public ServiceA getServiceA() {
return serviceA;
}
}
成功启动:
2025-03-04T15:57:52.092+08:00 INFO 51332 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 23 endpoint(s) beneath base path '/actuator'
2025-03-04T15:57:52.174+08:00 INFO 51332 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
2025-03-04T15:57:52.177+08:00 INFO 51332 --- [ main] c.e.M.MySpringBootTestApplication : Started MySpringBootTestApplication in 4.87 seconds (process running for 5.16)
2 - 使用 @Lazy
延迟加载
在其中任意一个依赖上或者两个依赖都添加 @Lazy
,让 Spring 延迟注入代理对象,直到实际使用时才初始化。
package com.example.MySpringBootTest.service.impl;
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;
}
package com.example.MySpringBootTest.service.impl;
import jdk.jfr.Label;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
@Service
public class ServiceB {
@Autowired
private ServiceA serviceA;
}
正常启动:
2025-03-04T16:05:56.009+08:00 INFO 51415 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 23 endpoint(s) beneath base path '/actuator'
2025-03-04T16:05:56.112+08:00 INFO 51415 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
2025-03-04T16:05:56.116+08:00 INFO 51415 --- [ main] c.e.M.MySpringBootTestApplication : Started MySpringBootTestApplication in 5.381 seconds (process running for 5.73)