org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'hello.itemservice.config.MemoryConfig': Unsatisfied dependency expressed through constructor parameter 0;
nested exception is org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'hello.itemservice.config.MemoryConfig': Requested bean is currently in creation: Is there an unresolvable circular reference?
@Configuration 클래스에 빈을 등록하는 메소드를 정의하고 이 객체를 주입받으면 이런 예외가 발생한다.
Bean이 현재 생성되고 있어서 MemoryConfig의 dependency를 주입하는데 있어서 Unsatisfied 하다. 혹시 순환 참조가 있는지 확인해봐라.
대충 이런 느낌
@Configuration
@RequiredArgsConstructor
public class MemoryConfig {
private final ItemRepository itemRepository;
@Bean
public ItemService itemService() {
return new ItemServiceV1(itemRepository);
}
@Bean
public ItemRepository itemRepository() {
return new MemoryItemRepository();
}
}
이 클래스에는 ItemRepository를 빈으로 등록하는 메소드가 있고, ItemRepository를 주입받는다.
ApplicationContext 초기화 과정에서 컴포넌트 스캔으로 MemoryConfig를 빈으로 등록하게 된다.
이때 ItemRepository에 대한 의존성 주입도 이루어져야 한다. 하지만 ItemRepository는 아직 빈으로 등록되지 않았으므로 예외가 발생하게 되는 것이다.
빈을 등록한 곳에서 해당 빈을 주입받으면 안된다.
맨 처음에 이런식으로 작성한 이유가 있었다.
ItemService를 빈으로 등록할 때, ItemRepository 객체가 필요한데, itemRepository()를 쓰면 new MemoryItemRepository()를 통해 객체를 새로 생성해서 전달하게 되므로 이미 빈으로 등록한 ItemRepository 객체를 사용하지 않고 새로운 객체를 주입해서 싱글톤이 유지되지 않는 게 아닐까 했었다.
근데 이건 걱정할 필요가 없다고 한다.
ItemService가 ItemRepository를 필요로 하는 것처럼, 빈 등록 메소드 A에서 필요한 객체가 빈 등록 메소드 B로 정의된 경우가 많은데, 이때 의존성을 주입하기 위해 메소드 B를 여러번 호출해도 메소드를 호출할때마다 매번 객체가 새로 생성되는 것을 방지하기 할 수 있다.
스프링은 MemoryConfig에 대한 프록시 객체를 먼저 생성하고, 이 프록시 객체가 해당 메소드의 호출을 가로채서 해당 빈을 인자로 넣어준다. 이를 통해 싱글톤을 유지할 수 있는 것이다.
결론적으로 코드는 이런식으로 작성해야 한다.
@Configuration
public class MemoryConfig {
@Bean
public ItemService itemService() {
return new ItemServiceV1(itemRepository());
}
@Bean
public ItemRepository itemRepository() {
return new MemoryItemRepository();
}
}
또는 이렇게 작성해야 한다.
@Configuration
public class MemoryConfig {
@Bean
public ItemService itemService(ItemRepository itemRepository) {
return new ItemServiceV1(itemRepository);
}
@Bean
public ItemRepository itemRepository() {
return new MemoryItemRepository();
}
}
'Spring' 카테고리의 다른 글
[Spring] invalid value type for attribute 'factorybeanobjecttype': java.lang.string (0) | 2024.03.14 |
---|---|
[Gradle] Caused by: java.net.BindException: Address already in use 에러 (Spring boot) (0) | 2024.03.01 |