문제 발생
SpringBoot로 개발을 하고 실행시켜 보니 아래와 같은 오류가 나타났다.
Parameter 0 of constructor in XXX.member.controller.MemberController required a single bean, but 2 were found:
- memberServiceImpl: defined in file [/XXX/out/production/classes/com/travelplan/member/service/MemberServiceImpl.class]
- memberService: defined by method 'memberService' in class path resource [XXX/member/config/MemberConfig.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.
원인 분석
Parameter 0 of constructor in XXX.member.controller.MemberController required a single bean, but 2 were found:
- memberServiceImpl: defined in file [/XXX/out/production/classes/com/travelplan/member/service/MemberServiceImpl.class]
- memberService: defined by method 'memberService' in class path resource [XXX/member/config/MemberConfig.class]
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
MemberController에서 MemberService 빈을 찾을 때 MemberServiceImpl 클래스와 MemberConfig 클래스에서 2개의 MemberService 빈이 발견되어 컨트롤러에서 명확한 빈을 주입하지 못하는 오류 같다.
이 오류를 해결하려면 같은 이름의 빈이 2개 있으므로
@Primary 어노테이션을 사용하여 MemberSerivceImpl 클래스나 MemberConfig 클래스의 MemberSerivce 빈을 기본으로 주입할 빈으로 지정해 주거나,
@Qualifier 어노테이션을 사용하여 MemberController에서 MemberService에 필요한 빈의 이름을 명시해 줘서 해결하면 된다. (이때 MemberServiceImpl과 MemberConfig 중 하나는 MemberService를 빈 등록할 때 빈 이름을 변경해줘야 한다.)
하지만 위와 같은 방법을 사용해서 해결하는 게 끌리지 않아서 더 찾아보고 로그를 다시 확인했다.
This may be due to missing parameter name information
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.
파라미터 이름 정보가 누락되어서 오류가 생겼을 수도 있다고 한다.
또한 컴파일러가 '-parameters' 플래그를 사용하도록 구성되었는지 확인해 보라고 한다.
이 로그를 중심으로 찾아보니 해당 오류는 @Primary나 @Qualifier 어노테이션을 쓰지 않고 해결할 수 있는 방법이 있었다.
Spring Boot 3.2부터 자바 컴파일러에 -parameters 옵션을 넣어줘야 어노테이션의 이름을 생략할 수 있다.
주로 아래 어노테이션을 사용할 때 문제가 발생한다.
- @RequestParam
- @PathVariable
- @Autowired
- @ConfigurationProperties
내가 문제가 생긴 곳은 @RequiredArgsConstructor를 사용한 부분 같다.
@Service
@RequiredArgsConstructor
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository;
/*
@Autowired
public MemberServiceImpl(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
*/
}
이 어노테이션은 final 필드를 확인해서 주석 부분을 자동 생성한다.
따라서 직접적으로 @Autowired를 사용하지는 않았지만 내부적으로 자동 생성된 @Autowired를 사용한다.
자동 생성된 @Autowired 생성자 부분을 보자. (주석 부분)
MemberRepository를 주입받을 때 변수 이름인 memberRepository를 통해서 memberRepository라는 이름의 스프링 빈을 찾는다.
하지만 파라미터명을 사용할 수 없기 때문에 이름으로 대상을 찾을 수 없다.
문제 해결
IntelliJ IDEA -> Setting에서 Gradle을 검색한다.
Build and run using을 위 그림과 같이 IntelliJ IDEA로 선택한 경우에만 문제가 발생한다고 한다.
따라서 아래 그림과 같이 Gradle로 변경하자. (Gradle이 컴파일 시점에 해당 옵션을 자동으로 적용해 준다.)
이 문제로 시간을 많이 써서 너무 아쉽다. (역시 개발은 설정이 반...)
도움 받은 곳
https://docs.google.com/document/d/1j0jcJ9EoXMGzwAA2H0b9TOvRtpwlxI5Dtn3sRtuXQas/edit