[Java/오류노트] Solved - Parameter 0 of constructor in xx required a single bean, but 2 were found
adjh54
2025. 3. 4. 20:03
728x170
해당 글에서는 하나의 Service 인터페이스에 이를 활용한 두 개의 구현체를 이용하는 경우 발생하는 에러에 대해서 알아봅니다.
1) 문제점
💡 문제점
- 아래와 같은 오류가 발생하였습니다. 해당 오류는 RedisSingleDataService 인터페이스에 대해서 구현체로 redisSingleDataServiceImpl와 redisSingleDataServiceImpl에서 구현하는 과정에서 발생하는 오류입니다.
Description: Parameter 0 of constructor in com.adjh.springbootredis.controller.RedisSingleDataController required a single bean, but 2 were found: redisCacheSingleDataServiceImpl: defined in file [/Users/leejonghoon/Desktop/workspace/adjh54/blog-codes/spring-boot-redis/build/classes/java/main/com/adjh/springbootredis/service/impl/RedisCacheSingleDataServiceImpl.class]redisSingleDataServiceImpl: defined in file [/Users/leejonghoon/Desktop/workspace/adjh54/blog-codes/spring-boot-redis/build/classes/java/main/com/adjh/springbootredis/service/impl/RedisSingleDataServiceImpl.class] This may be due to missing parameter name information Action: Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed Ensure that your compiler is configured to use the '-parameters' flag. You may need to update both your build tool settings as well as your IDE. (See https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#parameter-name-retention)
2) 해결방법
💡 해결방법
- 해당 문제점에서는Spring Boot의 의존성 주입(Dependency Injection) 과정에서 발생한 빈(Bean) 충돌 문제입니다.
- 여러 구현체의 존재: RedisSingleDataService 인터페이스에 대해 redisSingleDataServiceImpl과 redisCacheSingleDataServiceImpl 두 개의 구현 클래스가 있습니다. - 모호한 의존성 주입: RedisSingleDataController의 생성자가 RedisSingleDataService 타입의 빈을 필요로 하는데, 스프링은 두 개의 구현체 중 어떤 것을 주입해야 할지 결정하지 못합니다.
1. 해결방법 -1 : @Primary 어노테이션 사용
💡 해결방법 -1 : @Primary 어노테이션 사용
- Controller에서 호출하는 서비스 중 어떤 구현체를 우선 사용할지에 대해서 지정하는 @Primary을 구현체에 넣음으로써 수행합니다
[ 더 알아보기 ] 💡 @Primary - Spring Framework에서 동일한 타입의 여러 빈(Bean)이 등록되어 있을 때 자동 와이어링(autowiring)에서 우선적으로 사용할 빈을 지정하는 어노테이션입니다.
- 우선순위 지정: 같은 타입의 여러 빈이 있을 때 @Primary가 붙은 빈이 기본적으로 주입됩니다. - 모호성 해결: 자동 주입 시 발생할 수 있는 "NoUniqueBeanDefinitionException" 오류를 방지합니다. - 전역적 설정: @Qualifier와 달리 주입 지점마다 설정할 필요 없이, 구현 클래스에 한 번만 지정하면 됩니다.
💡 아래와 같이 두개의 구현체 중 RedisCacheSingleDataServiceImpl 내에 @Primary를 선언하면 우선적으로 RedisCacheSingleDataServiceImpl 구현체를 이용하겠다고 선언이 됩니다.
@Service@PrimarypublicclassRedisCacheSingleDataServiceImplimplementsRedisSingleDataService{
// 구현 내용
}
@ServicepublicclassRedisSingleDataServiceImplimplementsRedisSingleDataService{
// 구현 내용
}
💡 즉, 아래의 Controller에서 RedisSingleDataService에 대해서 호출되는 구현체는 @Primary를 선언한 RedisCacheSingleDataServiceImpl 입니다.
- Spring Framework에서 동일한 타입의 여러 빈(Bean)이 존재할 때 특정 빈을 명시적으로 지정하기 위한 어노테이션입니다.
- 세부 지정: 자동 와이어링(autowiring) 시 여러 후보 빈 중에서 어떤 빈을 주입할지 명확하게 지정합니다. - 유연한 선택: 같은 서비스 인터페이스에 대해 상황에 따라 다른 구현체를 선택적으로 사용할 수 있습니다. - 지점별 설정: @Primary와 달리 의존성 주입이 발생하는 각 지점마다 개별적으로 지정할 수 있습니다.
💡 아래의 예시와 같이 RedisCacheSingleDataServiceImpl 클래스 내에서는 @Service("redisSingleCacheService") 형태로 구성했고, RedisSingleDataServiceImpl 클래스 내에서는 @Service("redisSingleService")로 각각 서비스 빈에 이름을 지정하였습니다.
// 서비스 빈에 이름 지정@Service("redisSingleCacheService")publicclassRedisCacheSingleDataServiceImplimplementsRedisSingleDataService{
// 구현 내용
}
@Service("redisSingleService")publicclassRedisSingleDataServiceImplimplementsRedisSingleDataService{
// 구현 내용
}
💡 이를 호출하는 Controller에서는 @Qualifier를 이용하여서 특정 구현체의 이름을 입력하여 이를 불러오도록 합니다.
// 컨트롤러에서 @Qualifier로 특정 빈 지정하여 주입받기@RestControllerpublicclassRedisSingleDataController{
privatefinal RedisSingleDataService redisSingleDataService;
public RedisSingleDataController(@Qualifier("redisSingleCacheService") RedisSingleDataService redisSingleDataService) {
this.redisSingleDataService = redisSingleDataService;
}
// 컨트롤러 메서드들...
}