Spring循環依賴報錯Bean with name '**' has been injected into other beans [**] in its raw version as part


異常詳情

Bean with name ‘commonService’ has been injected into other beans [] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using ‘getBeanNamesOfType’ with the ‘allowEagerInit’ flag turned off, for example.**

springboot循環依賴解決

1. 循環依賴是什么?

Bean A 依賴 B,Bean B 依賴 A這種情況下出現循環依賴。
Bean A → Bean B → Bean A
更復雜的間接依賴造成的循環依賴如下。
Bean A → Bean B → Bean C → Bean D → Bean E → Bean A

2. 循環依賴會產生什么結果?

當Spring正在加載所有Bean時,Spring嘗試以能正常創建Bean的順序去創建Bean。
例如,有如下依賴:
Bean A → Bean B → Bean C
Spring先創建beanC,接着創建bean B(將C注入B中),最后創建bean A(將B注入A中)。

但當存在循環依賴時,Spring將無法決定先創建哪個bean。這種情況下,Spring將產生異常BeanCurrentlyInCreationException。

3.普通注入之間的循環依賴

比如:我現在有一個ServiceA需要調用ServiceB的方法,那么ServiceA就依賴於ServiceB,那在ServiceB中再調用ServiceA的方法,就形成了循環依賴。Spring在初始化bean的時候就不知道先初始化哪個,bean就會報錯。

public class ClassA { @Autowired ClassB classB; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
public class ClassB { @Autowired ClassA classA } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

解決辦法:

如何解決循環依賴,最好的方法是重構代碼,進行解耦,如果沒有時間重構,可以使用下面的方法:

(1)在你的配置文件中,在互相依賴的兩個bean的任意一個加上lazy-init屬性

<bean id="ServiceDependent1" class="org.xyz.ServiceDependent1" lazy-init="true"> <constructor-arg ref="Service"/> </bean> <bean id="ServiceDependent2" class="org.xyz.ServiceDependent2" lazy-init="true"> <constructor-arg ref="Service"/> </bean> 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(2)在你注入bean時,在互相依賴的兩個bean上加上@Lazy注解也可以

@Autowired @Lazy private ClassA classA; @Autowired @Lazy private ClassB classB; 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

構造器注入循環依賴實例

首先定義兩個相互通過構造器注入依賴的bean。

@Component public class CircularDependencyA { private CircularDependencyB circB; @Autowired public CircularDependencyA(CircularDependencyB circB) { this.circB = circB; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
@Component public class CircularDependencyB { private CircularDependencyA circA; @Autowired public CircularDependencyB(CircularDependencyA circA) { this.circA = circA; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
@Configuration @ComponentScan(basePackages = { "com.baeldung.circulardependency" }) public class TestConfig { } 
  • 1
  • 2
  • 3
  • 4
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { TestConfig.class }) public class CircularDependencyTest { @Test public void givenCircularDependency_whenConstructorInjection_thenItFails() { // Empty test; we just want the context to load } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

運行方法
givenCircularDependency_whenConstructorInjection_thenItFails
將會產生異常:BeanCurrentlyInCreationException: Error creating bean with name ‘circularDependencyA’:
Requested bean is currently in creation: Is there an unresolvable circular reference?

如何解決

(1)重新設計

重新設計結構,消除循環依賴。

(2)使用注解 @Lazy

一種最簡單的消除循環依賴的方式是通過延遲加載。在注入依賴時,先注入代理對象,當首次使用時再創建對象完成注入。

@Component public class CircularDependencyA { private CircularDependencyB circB; @Autowired public CircularDependencyA(@Lazy CircularDependencyB circB) { this.circB = circB; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用@Lazy后,運行代碼,可以看到異常消除。
(3)使用Setter/Field注入
Spring文檔建議的一種方式是使用setter注入。當依賴最終被使用時才進行注入。對前文的樣例代碼少做修改,來觀察測試效果。

@Component public class CircularDependencyA { private CircularDependencyB circB; @Autowired public void setCircB(CircularDependencyB circB) { this.circB = circB; } public CircularDependencyB getCircB() { return circB; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
@Component public class CircularDependencyB { private CircularDependencyA circA; private String message = "Hi!"; @Autowired public void setCircA(CircularDependencyA circA) { this.circA = circA; } public String getMessage() { return message; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { TestConfig.class }) public class CircularDependencyTest { @Autowired ApplicationContext context; @Bean public CircularDependencyA getCircularDependencyA() { return new CircularDependencyA(); } @Bean public CircularDependencyB getCircularDependencyB() { return new CircularDependencyB(); } @Test public void givenCircularDependency_whenSetterInjection_thenItWorks() { CircularDependencyA circA = context.getBean(CircularDependencyA.class); Assert.assertEquals("Hi!", circA.getCircB().getMessage()); } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

(4) 使用@PostConstruct

@Component public class CircularDependencyA { @Autowired private CircularDependencyB circB; @PostConstruct public void init() { circB.setCircA(this); } public CircularDependencyB getCircB() { return circB; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
@Component public class CircularDependencyB { private CircularDependencyA circA; private String message = "Hi!"; public void setCircA(CircularDependencyA circA) { this.circA = circA; } public String getMessage() { return message; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

(5)實現ApplicationContextAware與InitializingBean

@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; } } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
@Component public class CircularDependencyB { private CircularDependencyA circA; private String message = "Hi!"; @Autowired public void setCircA(CircularDependencyA circA) { this.circA = circA; } public String getMessage() { return message; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM