1. 배경
- 진행하던 프로젝트에서 Spring디버깅하면서 본 아이디어를 적용해보고자 하였다. 특정 인터페이스의 구현체들을 List에 담고 list를 순회하며 구현체의 응답값이 있을 경우 바로 return하는 구조이다.
@Service
@RequiredArgsConstructor
public class ExternalAddressApiServiceImpl implements ExternalAddressApiService{
private final List<ExternalAddressApi> externalAddressApi;
@Override
public AddressApiResponse searchAddress(String query, String analyzeType, Integer page, Integer size) {
for (ExternalAddressApi addressApi : externalAddressApi) {
AddressApiResponse result = addressApi.searchAddress(query, page, size);
if (result != null && !CollectionUtils.isEmpty(result.getContents())) {
return result;
}
}
return null;
}
@Override
public AddressApiResponse searchAddress(String query) {
return searchAddress(query, null, null, null);
}
}
- 여기서 ExternalAddressApi 구현체는 KakaoAddressApi와 NaverAddressApi이다. 각 구현체는 RestTemplate bean을 주입받는다.
@Bean
public RestTemplate kakaoRestTemplate(RestTemplateBuilder restTemplateBuilder) {
생략
}
@Bean
public RestTemplate naverRestTemplate(RestTemplateBuilder restTemplateBuilder) {
생략
}
2. 문제1 : Bean 중복에 의한 의존성 주입 결정
- 처음에는 KakaoApi와 NaverApi 모두 RestTemplate bean을 아래와 같은 코드로 주입받았다.
private final RestTemplate restTemplate;
- 결과는 아래와 같이 bean이 여러개라는 에러가 발생했다.
Parameter 0 of constructor in com.sun.external.api.KakaoAddressApi required a single bean, but 2 were found:
- kakaoRestTemplate: defined by method 'kakaoRestTemplate' in class path resource [com/sun/external/config/RestTemplateConfig.class]
- naverRestTemplate: defined by method 'naverRestTemplate' in class path resource [com/sun/external/config/RestTemplateConfig.class]
- 그래서 우선 @Qualifier를 적용하여 문제를 해결하였다.
KakaoAddressApi.java
@Qualifier("kakaoRestTemplate")
private final RestTemplate restTemplate;
-----------------------------------------------
NaverAddressApi.java
@Qualifier("naverRestTemplate")
private final RestTemplate restTemplate;
- 찾다보니 중복빈이 있을 때 필드명과 같은 빈을 찾는다고 해서 아래 방법도 사용해보았다.
KakaoAddressApi.java
private final RestTemplate kakaoRestTemplate;
-----------------------------------------------
NaverAddressApi.java
private final RestTemplate naverRestTemplate;
3. 문제2 : List에 빈 추가 시 우선순위 문제
- ExternalAddressApiServiceImpl에서 List에 bean을 자동으로 주입받게 되는데, 이때 순서를 내가 정할 수 없다는 문제가 있었다. 특정 상황에서 특정 API가 먼저 호출되게 하고 싶다면? Bean 등록 우선순위가 애플리케이션 시작 때마다 달라진다면?
- 이 문제 역시 @Order 애노테이션을 이용해 해결할 수 있었다.
@Order(1)
public class KakaoAddressApi implements ExternalAddressApi {
NaverAddressApi.java
@Order(2)
public class NaverAddressApi implements ExternalAddressApi{
KakaoAddressApi.java
- 애노테이션을 이용해 순서를 지정해주었더니 내가 원하는 호출 순서가 보장되었다.