Using service discovery to look up a service

2026. 1. 4. 21:27Spring Microservice/Service Discovery

🔍 Service Discovery를 이용한 서비스 조회 (Eureka 기반)

마이크로서비스 아키텍처(MSA)에서 서비스 간 통신은 가장 핵심적인 요소 중 하나입니다.
특히 서비스의 물리적인 위치(IP, 포트)를 직접 알지 않고도 다른 서비스를 호출할 수 있어야 진정한 클라우드 네이티브 구조라고 할 수 있습니다 ☁️

이번 챕터에서는 Licensing ServiceOrganization Service를 호출하는 과정을 통해
📌 Spring Cloud Eureka 기반 Service Discovery가 실제로 어떻게 동작하는지 자세히 살펴보겠습니다.

 

🎯 목표: 서비스 위치를 모른 채 서비스 호출하기

이번 섹션의 핵심 목표는 다음과 같습니다 👇

Licensing Service가 Organization Service의 실제 위치를 전혀 알지 못한 상태에서,
Eureka를 통해 Organization Service를 조회하고 호출하는 방법 이해하기

이를 위해 Licensing Service는 Eureka를 통해 Organization Service의 물리적 위치를 조회합니다.

 

🧩 사용되는 Spring / Netflix Client 라이브러리들

Spring Cloud에서는 Spring Cloud Load Balancer를 통해
여러 방식의 서비스 호출 추상화를 제공합니다.

이번 예제에서는 추상화 수준이 낮은 것부터 높은 것까지
3가지 클라이언트 라이브러리를 비교하며 살펴봅니다 🔄

 

📚 이번에 다룰 3가지 클라이언트

아래 순서대로 점점 사용이 쉬워지는 구조입니다 👇

1️⃣ Spring Discovery Client
2️⃣ Discovery Client가 적용된 RestTemplate
3️⃣ Netflix Feign Client

 

각각의 특징은 다음과 같습니다.

🔹 1. Spring Discovery Client

  • 가장 낮은 수준의 추상화
  • 개발자가 직접 서비스 인스턴스 목록을 조회하고 선택
  • 유연하지만 코드가 다소 복잡해질 수 있음

🔹 2. Discovery Client–enabled RestTemplate

  • Spring이 제공하는 향상된 RestTemplate
  • Load Balancer가 자동으로 서비스 인스턴스를 선택
  • 코드 복잡도 ↓, 생산성 ↑

🔹 3. Netflix Feign Client

  • 가장 높은 수준의 추상화
  • 인터페이스 선언만으로 서비스 호출 가능
  • 마치 로컬 메서드 호출처럼 사용 가능 ✨

 

🧪 하나의 엔드포인트로 모든 방식 테스트하기

이번 예제의 핵심 설계 포인트 중 하나는 💡
세 가지 클라이언트 방식을 하나의 API 엔드포인트에서 모두 테스트할 수 있도록 구성했다는 점입니다.

이를 위해 Licensing Service에 헬퍼(helper)용 라우트를 추가했습니다.

 

🚏 LicenseController에 추가된 새로운 라우트

📂 경로

src/main/java/com/optimagrowth/license/controller/LicenseController.java

 

🧾 새로 추가된 API 코드

@RequestMapping(value="/{licenseId}/{clientType}",
method = RequestMethod.GET)
public License getLicensesWithClient(
@PathVariable("organizationId") String organizationId,
@PathVariable("licenseId") String licenseId,
@PathVariable("clientType") String clientType) {

    return licenseService.getLicense(organizationId,
                                     licenseId,
                                     clientType);
}

 

🧠 이 라우트의 핵심 역할

  • clientType 파라미터를 통해
    👉 어떤 방식의 클라이언트를 사용할지 결정
  • 하나의 API로 Discovery / Rest / Feign 방식 모두 테스트 가능
  • 실습 및 비교에 매우 유용한 구조 👍

 

🔑 clientType으로 전달 가능한 값들

라우트에서 전달 가능한 clientType 값은 다음과 같습니다 👇

clientType 값 설명
discovery Discovery Client + 기본 RestTemplate 사용
rest Load Balancer가 적용된 RestTemplate 사용
feign Netflix Feign Client 사용

 

⚠️ NOTE (중요)

하나의 코드베이스에서 3가지 방식을 모두 사용하기 때문에,
실제 설명상 필요 없어 보이는 어노테이션이 존재할 수 있습니다.

예를 들어 👇

  • @EnableDiscoveryClient
  • @EnableFeignClients

👉 특정 클라이언트만 설명하는 부분에서도
👉 모든 예제를 한 코드베이스에서 실행 가능하도록 유지하기 위해 포함되어 있습니다.

💡 실제 프로젝트에서는 자신의 목적에 맞는 방식 하나만 선택하면 됩니다.

 

🧠 LicenseService의 핵심 로직

📂 경로

src/main/java/com/optimagrowth/license/service/LicenseService.java

이 클래스에서는 clientType에 따라 Organization Service를 조회하는 로직이 추가되었습니다.

 

🔁 retrieveOrganizationInfo() 메서드

  • clientType 값을 기준으로
  • 어떤 방식의 클라이언트를 사용할지 결정
  • Organization Service 인스턴스 조회 수행

🧾 getLicense() 메서드 전체 코드

public License getLicense(String licenseId,
                           String organizationId,
                           String clientType){

    License license = licenseRepository
        .findByOrganizationIdAndLicenseId(organizationId, licenseId);

    if (null == license) {
        throw new IllegalArgumentException(String.format(
            messages.getMessage("license.search.error.message", null, null),
            licenseId, organizationId));
    }

    Organization organization =
        retrieveOrganizationInfo(organizationId, clientType);

    if (null != organization) {
        license.setOrganizationName(organization.getName());
        license.setContactName(organization.getContactName());
        license.setContactEmail(organization.getContactEmail());
        license.setContactPhone(organization.getContactPhone());
    }

    return license.withComment(config.getExampleProperty());
}

 

🔍 이 메서드의 처리 흐름 요약

1️⃣ 라이선스 정보 조회 (Postgres DB)
2️⃣ clientType에 따라 Organization Service 호출
3️⃣ Organization 정보가 존재하면 License 객체에 병합
4️⃣ 최종 License 객체 반환

 

📦 각 클라이언트 구현 위치

각 방식별 클라이언트 구현체는 다음 경로에 위치합니다 📁

src/main/java/com/optimagrowth/license/service/client

이 패키지 안에 다음과 같은 구현들이 존재합니다 👇

  • Discovery Client 기반 구현
  • RestTemplate 기반 구현
  • Feign Client 기반 구현

 

🌐 실제 호출 테스트용 엔드포인트

각 방식의 클라이언트를 테스트하기 위해
다음 GET 요청을 사용할 수 있습니다 🚀

http://<licensing service Hostname/IP>:<licensing service Port>/v1/
organization/<organizationID>/license/<licenseID>/<client type>

✅ client type 예시

  • feign
  • discovery
  • rest

 

🎉 마무리 정리

이번 글에서는 다음 내용을 살펴봤습니다 ✅

✔ Eureka를 활용한 서비스 디스커버리 개념
✔ Licensing Service → Organization Service 호출 구조
✔ 3가지 Spring/Netflix 클라이언트 방식 비교
✔ clientType 기반 동적 클라이언트 선택 구조
✔ 실습용 헬퍼 라우트 설계 의도