Spring cloud 환경에서 feign 사용

박우영·2023년 6월 15일
0

자바/코틀린/스프링

목록 보기
27/37

이어서...

Spring Cloud Gateway 로 연결 후에 RestTemplate 를 사용하여 받아와도 되지만 하나하나 파싱해줘야 하는 번거로움을 개선 시켜줄 Feign 을 사용해 보기로했다. 원래 Spring cloud 환경을 위해 만들어진 라이브러리인만큼 한번쯤은 사용해 봐야겠다고 생각했는데 막상 써보니 엄청 편했다.


build.gradle

	implementation "org.springframework.cloud:spring-cloud-starter-openfeign"

Feign Client

@FeignClient(name = "Rule", url = "http://localhost:9000") //${custom.server}
public interface StudyRuleFeign {
    @RequestMapping(method = RequestMethod.GET, value = "/api/rule/v1/search") //studyrule
    RsData<List<StudyRuleConsumeDto>> getStudyRule();
}

인터페이스로 Feign 을 정의하고 호출할 Controller 를 정의해보자

Controller

    @GetMapping("/api/test")
    public RsData<List<StudyRuleConsumeDto>> test() {
        return feign.getStudyRule();
    }

호출되는 rule코드

    /**
     * 전체 리스트 조회
     * return:
     * List<name, about, xp, count, provider, difficulty>
     */
    @GetMapping("/v1/search")
    @Operation(summary = "모든 규칙을 검색합니다.", tags = "조회")
    public RsData<List<RuleDto>> searchRule() {
        List<Rule> rules = ruleService.getRuleList();
        List<RuleDto> collect = rules.stream()
                .map(RuleDto::new)
                .toList();
        return new RsData<>("S-1","Rule 목록" ,collect);
    }

간단한 연결 테스트를 하기위한거라 따로 데이터를 넣어주진 않았다.

Postman 을 활용하여 호출

쿼리도 잘 나가는데

om.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.baekersolved.domain.dto.response.RsData` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
 at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 2]
	at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:67) ~[jackson-databind-2.14.3.jar:2.14.3]
	at com.fasterxml.jackson.databind.DeserializationContext.reportBadDefinition(DeserializationContext.java:1909) ~[jackson-databind-2.14.3.jar:2.14.3]
	at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:408) ~[jackson-databind-2.14.3.jar:2.14.3]
	at com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1354) ~[jackson-databind-2.14.3.jar:2.14.3]
	at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1420) ~[jackson-databind-2.14.3.jar:2.14.3]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:352) ~[jackson-databind-2.14.3.jar:2.14.3]
	at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:185) ~[jackson-databind-2.14.3.jar:2.14.3]
	at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:323) ~[jackson-databind-2.14.3.jar:2.14.3]
.
.
.

다음과 같은 에러 발생 생성자가 없다는 뜻이었고 Feign을 호출 하기 위해선 생성자가 필요하다 는 뜻 같아서 RsData 에 @NoArgsConstructor 를 추가 해줬다.

호출이 성공된 것을 확인 해봤습니다. 파싱을 여러번 해야하는 API 에 대해 RestTemplate 와 비교해 보겠습니다.

Feign vs RestTemplate

넘어오는 API 값 입니다. swagger 에선 1개의 값만 나오지만 여러개의 값이 있는 데이터 입니다.

DTO

{
  "resultCode": "string",
  "msg": "string",
  "data": [
    {
      "id": 0,
      "baekJoonName": "string",
      "bronze": 0,
      "sliver": 0,
      "gold": 0,
      "diamond": 0,
      "ruby": 0,
      "platinum": 0,
      "solvedCount": 0
    }
  ],
  "success": true,
  "fail": true
}

RestTemplate

    public RsData<List<MemberDto>> getMemberDtoList() throws ParseException {
        RestTemplate restTemplate = new RestTemplate();
        String jsonStr = restTemplate.getForObject(MEMBER_URL, String.class); // Memeber api
        JSONParser jsonParser = new JSONParser();
        Object object = jsonParser.parse(jsonStr);

        JSONObject jsonObject = (JSONObject) object;
        JSONArray jsonArray = (JSONArray) jsonObject.get("data");
        for (Object o : jsonArray) {
            JSONObject parseJson = (JSONObject) o;
            MemberDto memberDto = new MemberDto(
                    (Long) parseJson.get("id"), (String) parseJson.get("baekJoonName"),
                    (int) parseJson.get("bronze"), (int) parseJson.get("silver"),
                    (int) parseJson.get("gold"), (int) parseJson.get("platinum"),
                    (int) parseJson.get("diamond"), (int) parseJson.get("ruby"));
            memberDtoList.add(memberDto);
        }
        return RsData.of("S-1", "회원데이터", memberDtoList);
    }

Feign

Controller

    @RequestMapping(method = RequestMethod.GET, value = "/api/member/get/v1/all")
    RsData<List<MemberDto>> getMember();

Service

public RsData<List<MemberDto>> getMemberDtoList() {
    return feign.getMember();
}

값을 많이 받아와야하고 복잡한 파싱이 들어갈 수록 매우 유용하게 사용 할 수있다.

회고


간단하게 호출 할 수있지만 Spring webflux 환경은 비동기 방식으로 처리된다. 따라서 이러한 호출하나하나의 동시성을 해결해줘야하고 최종적으론 DB commit 수준을 고려하든 DB Lock 을 고려하든 이러한 이슈를 하나하나 씩 해결해 나가고자 합니다.

0개의 댓글