직장동료가 테스트 코드를 작성하려 하니 OpenFeign(내가 작성한 코드)에서 순환참조가 일어나 테스트 코드가 제대로 돌아가지 않는다고 한다. 어서 해결해보자.
환경: spring boot + GraphQL
OpenFeign 코드
1
2
3
4
5
6
7
8
9
10
11
@Service
@RequiredArgsConstructor
public class OpenFeignServiceImpl implements OpenFeignService {
private final OpenFeign sendOpenFeign; // 아래의 OpenFeign interface를 참조
@Override
public Response getResponse(final Input input) {
return sendOpenFeign.getResponse(input);
}
}
1
2
3
4
5
6
7
@FeignClient(name = "Client", url = "${client.url}", configuration = OpenFeignConfig.class)
public interface OpenFeign {
@GetMapping(value = "/api/v1/test/{input}", consumes = "application/json")
Response getResponse(@PathVariable("input") String input);
}
코드를 확인해보면,
OpenFeignServiceImpl 에서 OpenFeign 를 주입받아서 OpenFeign 의 getResponse 메소드를 사용하는 형태이다.
에러 화면

나는 mvcResourceUrlProvider를 참조하지 않았는데, 참조되어서 저 mvcResourceUrlProvider가 Graphql Servlet을 참조하고 … 꼬리를 물어서 순환참조가 되었다.
순환참조가 일어나는 이유
OpenFeign은 RESTFul Service를 쉽게 부르기 위한 라이브러리이고, mvcResourceUrlProvider은 정적리소스에 url을 제공하는 스프링 빈이다.
OpenFeign의 value인 “/api/v1/test/{input}” 가 정적인 url이라서 mvcResourceUrlProvider을 부르는 것으로 판단했다.
순환참조를 끊어내는 방법
순환참조를 끊어내기 위해 빈을 늦게 생성해주면 되는데, 2가지의 옵션이 있다.
- @Lazy
- ObjectProvider
하지만 실질적으로 @Lazy는 순환참조를 제대로 끊어내지 못하는데, 그 이유의 둘의 차이에 있다. @Lazy는 단순히 만드는 걸 늦게 만들게 하는 어노테이션이고, ObjectProvider는 실제 사용될때 생성하게 만들어주는 빈이기 때문에 ObjectProvider 를 사용해야 순환참조가 끊긴다.
1
2
3
4
5
6
7
8
9
10
11
@Service
@RequiredArgsConstructor
public class OpenFeignServiceImpl implements OpenFeignService {
private final ObjectProvider<OpenFeign> sendOpenFeign; // ObjectProvider로 한번 감싼서 참조한다.
@Override
public Response getResponse(final Input input) {
return sendOpenFeign.getObject.getResponse(input);
}
}
결국 ObjectProvider 를 사용해서 문제는 해결되었다… 욕 먹어서 배부르다.. 하하
번외
근데 왜 mvcResourceUrlProvider 는 graphqlServletRegistrationBean를 왜 참조하지?
mvcResourceUrlProvider는 Spring Boot에서 제공하는 웹 관련 기능의 필수적인 부분인 GraphQL 요청을 처리하는 데 필요하기 때문에 간접적으로 graphqlServletRegistrationBean을 참조합니다.
그럼 gql 쓰면 무조건 ObjectProvider 써야 하나?
graphql과 spring boot 에서 제공하는 웹 관련 기능을 같이 사용하게 되면 ObjectProvider 혹은 다른 lazy 를 권장합니다.