异常分析
Spring Boot 出现BeanCurrentlyInCreationException: Error creating bean with name: Requested bean is currently in creation异常是因为出现了两个bean相互依赖。如果 bean A依赖于bean B,而bean B又依赖于bean A,则将产生BeanCurrentlyInCreationException异常。
BEAN A -> BEAN B -> BEAN A (两个bean循环依赖)
BEAN A -> BEAN B -> BEAN C -> BEAN A (三个bean循环依赖)
当 spring boot 应用程序加载所有 bean 时,它会尝试自动连接依赖 bean。如果两个 bean 处于循环依赖关系中,则每个 bean 将等待另一个 bean 加载。加载 bean 时会出现死锁。因此,Spring Boot 应用程序将抛出异常。
如果 spring boot 应用程序中的两个或多个bean参与循环依赖,则spring boot应用程序无法在应用程序上下文中加载任何bean,因为每个bean 依赖于另一个bean。Spring boot 无法决定在循环依赖中首先加载哪个bean。因此,在将 bean 加载到应用程序上下文中时,spring boot 会抛出异常。
出现循环依赖的示例:
package com.demo;
public interface Animal {
String getName();
}
package com.demo;
import org.springframework.stereotype.Component;
@Component
public class Lion implements Animal {
public Lion(Tiger tiger) {
}
@Override
public String getName() {
return "Lion";
}
}
package com.demo;
import org.springframework.stereotype.Component;
@Component
public class Tiger implements Animal {
public Tiger(Lion lion){
}
@Override
public String getName() {
return "Tiger";
}
}
项目启动后会报以下错误:
***************************
APPLICATION FAILED TO START
***************************
Description:
The dependencies of some of the beans in the application context form a cycle:
┌─────┐
| lion defined in file [D:\project\study\java\springbean-demo\target\classes\com\demo\Lion.class]
↑ ↓
| tiger defined in file [D:\project\study\java\springbean-demo\target\classes\com\demo\Tiger.class]
└─────┘
解决方案1:
循环依赖是由于编程或架构的问题。遍历属于循环依赖的 bean,考虑重新设计 bean。这将解决异常。组件必须加载到分层依赖模型而不是循环模型中。为了解决这个异常,应该重新设计 bean 的加载顺序。
解决方案2:
循环依赖中的 bean 可以使用 @Autowired 注释加载。@Autowired 注释创建一个 bean 并加载依赖项。这将解决异常。但是,如果 bean 中的方法相互依赖,则会导致异常。
@Component
public class Lion implements Animal {
@Autowired
private Tiger tiger;
@Override
public String getName() {
tiger.getName();
return "Lion";
}
}
@Component
public class Tiger implements Animal {
@Autowired
private Lion lion;
@Override
public String getName() {
lion.getName();
return "Tiger";
}
}
解决方案3
Spring Boot 应用程序支持 bean 的延迟加载。@Lazy 注释在需要时加载 bean,而不是在开始时加载它。在创建 bean 并将其加载到上下文中后,将注入 bean。首先将创建循环依赖项中的 bean,然后将其他 bean 注入 bean。
@Component
public class Lion implements Animal {
public Lion(@Lazy Tiger tiger) {
}
@Override
public String getName() {
return "Lion";
}
}
@Component
public class Tiger implements Animal {
public Tiger(@Lazy Lion lion){
}
@Override
public String getName() {
return "Tiger";
}
}
解决方案4
spring boot 注解@PostConstruct 将用于在构造函数方法被调用后执行一个方法。可以使用后构造方法启动循环依赖 bean。Bean 将首先使用构造函数创建,然后将使用带注释的 @PostConstruct 方法创建 bean。
@Component
public class Lion implements Animal {
@Autowired
Tiger tiger;
@PostConstruct
public void load() {
tiger.setLion(this);
}
@Override
public String getName() {
return "Lion";
}
public void setTiger(Tiger tiger) {
this.tiger = tiger;
}
}
@Component
public class Tiger implements Animal {
@Autowired
Lion lion;
@PostConstruct
public void load() {
lion.setTiger(this);
}
@Override
public String getName() {
return "Tiger";
}
public void setLion(Lion lion) {
this.lion = lion;
}
}
解决方案5
@Autowired 注解可以在 setter 方法中使用。可以使用 @Autowired setter 方法分配 Bean。首先加载 bean,然后调用 setter 方法来自动连接其他 bean。
@Component
public class Lion implements Animal {
Tiger tiger;
@Override
public String getName() {
return "Lion";
}
@Autowired
public void setTiger(Tiger tiger) {
this.tiger = tiger;
}
}
@Component
public class Tiger implements Animal {
Lion lion;
@Override
public String getName() {
return "Tiger";
}
@Autowired
public void setLion(Lion lion) {
this.lion = lion;
}
}
翻译自:https://www.yawintutor.com/beancurrentlyincreationexception-error-creating-bean-with-name-requested-bean-is-currently-in-creation/