Netflix의 Eureka를 이용해서 디스커버리 서비스를 구현
클라우드 환경이 되면서 서비스가 오토 스케일링등에 의해서 동적으로 생성되거나 컨테이너 기반의 배포로 인해서, 서비스의 IP가 동적으로 변경.
이 때, 서비스 클라이언트가 서비스를 호출할때 서비스의 위치 (즉 IP주소와 포트)를 알아낼 수 있는 기능을 서비스 디스커버리(Service discovery)라고 부름
- 클라이언트 사이드 디스커버리 패턴(Client-Side Discovery Pattern)
- 서비스 인스턴스의 네트워크 위치를 찾고 로드밸런싱하는 역할을 클라이언트가 담당하는 방식
- 서버 사이드 디스커버리 패턴(Server-Side Discovery Pattern)
- 서버 쪽에서 디스커버리 로직을 구현한 방식
Eureka 서버와 클라이언트
discovery-service 프로젝트 생성
Eureka Server 활성화
#application.yml
server:
port: 8761
spring:
application:
name: discoveryservice
eureka:
client:
register-with-eureka: false # euraka의 registry에 등록할지 여부를 설정, 서버기 때문에
fetch-registry: false # registy에 있는 정보를 가져올지 여부를 결정
// aplication.java
package com.example.deliveryservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
실행 Euraka Dashboad 확인
instances currently registered with Eureka를 확인하면 아직 등록된 인스턴스가 없는 것을 확인
Eureka Client 생성
Eureka Discovery Client와 웹서비스 구현을 위한 dependency 추가
# application.yml 포트번호를 지정
server:
port: 9001
spring:
application:
name: test-user-service
eureka:
client:
register-with-eureka: true # 유레카 서버에 자신의 정보를 등록해줘야함
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
or
# application.yml 랜덤 포트번호 사용
server:
# 0으로 설정시 유효한 포트로 랜덤 설정함
# 0으로 여러개 생성시 test-user-service:0 사용하기 때문에 동일한 클라이언트로 식별
# 랜덤 포트를 사용하는 경우 유레카에서 식별할 수 있는 인스턴스 ID를 재정해 주는 것이 필요
port: 0
spring:
application:
name: test-user-service
eureka:
client:
register-with-eureka: true # 유레카 서버에 자신의 정보를 등록해줘야함
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
instance:
instance-id:${spring.application.name}:${spring.application.instance_id:${random.value}}
Eureka Client 활성화
// application.java
package com.example.testuserservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
실행 Euraka Dashboad 확인
instances currently registered with Eureka를 확인하면 application이 추가된것을 확인할 수 있음
* 아래의 EMERGENCY는 정보가 불일치 할 수도 있다는 의미
test-user-service 인스턴스를 하나 더 추가로 실행
같은 프로그램으로 여러개의 인스턴스를 실행 -> port번호 변경
STS Debug/Run Configurations 기능을 이용
실행시 9001, 9002의 포트로 2개의 인스턴스가 실행중이라는 출력
Netflix Zuul을 이용한 API Gateway 구현
first-service 프로젝트 생성
FirstServiceController 클래스 추가
// FirstServiceController
package com.example.firstservice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class FirstServiceController {
@GetMapping("/welcome")
public String welcome() {
return "Welcpme to the First service";
}
}
application.yml 작성
# application.yml
server:
port: 8081
spring:
application:
name: my-first-service
eureka:
client:
register-with-eureka: false
fetch-registry: false
Second-service 프로젝트 생성
SecondServiceController 클래스 추가
// SecondServiceController
package com.example.secondservice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/")
public class SecondServiceController {
@GetMapping("/welcome")
public String welcome() {
return "Welcpme to the Second service";
}
}
application.yml 작성
# application.yml
server:
port: 8082
spring:
application:
name: my-first-service
eureka:
client:
register-with-eureka: false
fetch-registry: false
Netflix ZUUL을 이용해 API Gateway 패턴 구현
zuul-service 프로젝트 생성
porm.xml의 의존성 수정
# porm.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
#버전 변경
<!-- <version>2.5.4</version> -->
<version>2.3.12.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>com.example.zuul-service</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>com.example.zuul-service</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
#zuul 의존성 추가
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-zuul -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
<version>2.2.9.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Application 클래스에 zuul활성화
# Application.java
package com.example.zuulservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@SpringBootApplication
@EnableZuulProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
application.yml에 route정보를 추가
# application.yml
server:
port: 8000
spring:
application:
name: my-zuul-service
zuul:
routes:
first-service:
path: /first-service/**
url: http://localhost:8081
second-serivce:
path: /second-service/**
url: http://localhost:8082
실행시 8000포트의 zuul-service로 부터 라우팅되는 것을 확인 가능
로그 확인을 위한 Zuul filter
서비스 라우팅 전에 로그를 남기는 필터를 추가
zuul-service 프로젝트의 porm.xml에 lombok 의존성 추가
lombok 설치, 확인
zuul-service 프로젝트에 ZuulLoggingFilter 클래스 생성
// ZuulLoggingFilter
package com.example.zuulservice;
import javax.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@Component
public class ZuulLoggingFilter extends ZuulFilter {
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() throws ZuulException {
log.info("start log >>>>");
// 요청 URI 정보를 로그에 기록
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
log.info(request.getRequestURI());
log.info("<<< end log");
return null;
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 0;
}
}
zuul-service, first-serivce, second-service 실행 후 필터 테스트
first-serivce나 second-service 접속시 로그 필터확인
Spring Cloud Gateway를 이용한 API Gateway 패턴을 구현
apigateway-service 프로젝트 생성
application.yml 파일 작성
# application.yml
server:
port: 8000
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
predicates:
- Path=/first-service/**
uri: http://localhost:8081
- id: second-serivce
predicates:
- Path=/second-service/**
uri: http://localhost:8082
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
기존의 first-service와 second-service에 대해 요청시 에러발생
서비스를 구분하기 위해 입력한 주소가 그대로 서비로 라우팅되는 것을 확인할 수 있음 ⇒ 라우팅된 서비스가 동작할 수 있도록 하기위해서 각 서비스에 서비스를 구분하는 정보를 받아들일 수 있도록 수정
first-service와 second-service의 맵핑 정보를 수정
// first-service
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/first-service") //수정
public class FirstServiceController {
@GetMapping("/welcome")
public String welcom() {
return "Welcome to the First Service";
}
}
// second-service
package com.example.demo;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/second-service") //수정
public class FirstServiceController {
@GetMapping("/welcome")
public String welcom() {
return "Welcome to the Second Service";
}
}
first-service, second-service를 재기동 후 동작 확인
* 단, 서비스를 직접 호출할 시에도 서비스 구분을 위해 부여한 경로를 포함해야하는 번거로움이 있음
Filter 1. java code를 이용한 Spring Cloud Gateway Filter
apigateway-service 프로젝트의 application.yml 파일 수정
# application.yml
server:
port: 8000
spring:
application:
name: apigateway-service
# cloud:
# gateway:
# routes:
# - id: first-service
# predicates:
# - Path=/first-service/**
# uri: http://localhost:8081
# - id: second-serivce
# predicates:
# - Path=/second-service/**
# uri: http://localhost:8082
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
FilterConfig 클래스 생성 - 라우팅 정보 및 요청/응답헤더 값을 설정
// Filterconfig
package com.example.apigatewayservice.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Filterconfig {
@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(r->r.path("/first-service/**")
.filters(f->f.addRequestHeader("first-request", "first-request-header")
.addResponseHeader("first-response", "first-response-header"))
.uri("http://localhost:8081"))
.route(r -> r.path("/second-service/**")
.filters(f -> f.addRequestHeader("second-request", "second-request-header")
.addResponseHeader("second-response", "second-response-header"))
.uri("http://localhost:8082"))
.build();
}
}
first-service, second-service 프로젝트에 mesage()메서드 추가
필터에서 추가한 요청 헤더의 내용을 출력하는 메서드
// first-service - firstServiceController
package com.example.firstservice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/first-service")
public class FirstServiceController {
@GetMapping("/welcome")
public String welcome() {
return "Welcpme to the First service";
}
@GetMapping("/message")
public String message(@RequestHeader(value="first-service", defaultValue = "NONE") String header) {
log.info(header);
return "First Service Request Header"+ header;
}
}
// second-service - secondServiceController
package com.example.secondservice;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/second-service")
public class SecondServiceController {
@GetMapping("/welcome")
public String welcome() {
return "Welcpme to the Second service";
}
@GetMapping("/message")
public String message(@RequestHeader(value="second-service", defaultValue = "NONE") String header) {
log.info(header);
return "First Service Request Header"+ header;
}
}
apigateway-service, first-service, second-service를 실행
apigateway로 접근시 log가 출력되고 response-Header가 변경되는것을 확인
Filter 2. 설정파일을 이용한 Spring Cloud Gateway Filter
기존의 프로젝트에서 수정하여 확인
FilterConfig 클래스에서 Configuration, Bean 어노테이션을 삭제 → 해당 클래스를 일반 클래스로 인식
// FilterConfig
package com.example.apigatewayservice.config;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
//@Configuration
public class Filterconfig {
// @Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(r->r.path("/first-service/**")
.filters(f->f.addRequestHeader("first-request", "first-request-header")
.addResponseHeader("first-response", "first-response-header"))
.uri("http://localhost:8081"))
.route(r -> r.path("/second-service/**")
.filters(f -> f.addRequestHeader("second-request", "second-request-header")
.addResponseHeader("second-response", "second-response-header"))
.uri("http://localhost:8082"))
.build();
}
}
application.yml파일에 라이팅, 필터 정보 추가
# application.yml
server:
port: 8000
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
predicates:
- Path=/first-service/**
uri: http://localhost:8081
filters:
- AddRequestHeader=first-request, first-request-header-from-yaml
- AddResponseHeader=first-response, first-response-header-from-yaml
- id: second-serivce
predicates:
- Path=/second-service/**
uri: http://localhost:8082
filters:
- AddRequestHeader=second-request, second-request-header-from-yaml
postman을 이용하여 apigateway 서비스로 first-service, second-service의 welcome 페이지 요청
apigateway로 접근시 log가 출력되고 response-Header가 변경되는것을 확인
Filter 3. Spring Cloud Gateway Custom Filter
Spring Cloud Gateway Filter의 인증, 로깅, 로케일 변경 등을 처리하는 사용자 정의 필터
요청 아이디(request.getId())와 처리상태코드(response.getStatusCode())를 반환하는 Pre필터와 Post필터를 추가
apigateway-service 프로젝트에 클래스, yml 작업
CustomFiler 클래스 생성
// CustomFilter
package com.example.apigatewayservice.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
// 설정 정보를 제공하는 클래스
public static class Config {
// 설정 정보가 필요한 경우 명시
}
public CustomFilter() {
super(Config.class);
}
// 필터의 동작을 정의한 메서드
@Override
public GatewayFilter apply(Config config) {
// custom pre filter
return (exchange, chain) -> {
// 요청이 전달되었을 때 요청 아이디를 로그로 출력
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Custom PRE FILTER: request id = {}", request.getId());
// custom post filter
// 응답의 처리상태코드를 로그로 출력
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
log.info("Custom POST FILTER: response code = {}", response.getStatusCode());
}));
};
}
}
application.yml등록
# application.yml
server:
port: 8000
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: first-service
predicates:
- Path=/first-service/**
uri: http://localhost:8081
filters:
- CustomFilter
# - AddRequestHeader=first-request, first-request-header-from-yaml
# - AddResponseHeader=first-response, first-response-header-from-yaml
- id: second-serivce
predicates:
- Path=/second-service/**
uri: http://localhost:8082
filters:
- CustomFilter
#- AddRequestHeader=second-request, second-request-header-from-yaml
#- AddResponseHeader=second-response, second-response-header-from-yaml
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
first-service, second-service에 check()메서드 추가
@GetMapping("/check")
public String check() {
return "check is called in First/Second Service";
}
apigateway-service, first-service, second-service 재기동
postman을 이용하여 apigateway 서비스로 check 서비스 요청후 동작 확인
Filter 4. Spring Cloud Gateway Global Filter
모든 라우팅에 적용(일반 필터, 커스텀 필터는 특정 라우팅에서만 동작)
공통적으로 적용해야 할 사항을 구현할 때 사용
모든 필터의 시작과 끝에서 동작
apigateway-service 프로젝트에서 수정
GlobalFilter 클래스 생성
코드는 CustomFilter와 유사함
//GlobalFilter
package com.example.apigatewayservice.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Mono;
@Component
@Slf4j
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {
// 설정 정보를 제공하는 클래스
@Data
public static class Config {
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
public GlobalFilter() {
super(Config.class);
}
// 필터의 동작을 정의한 메서드
@Override
public GatewayFilter apply(Config config) {
// custom pre filter
return (exchange, chain) -> {
// 요청이 전달되었을 때 요청 아이디를 로그로 출력
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Global Filter baseMessage = {}", config.getBaseMessage());
if (config.isPreLogger()) {
log.info("Global Filter is start ... request id = {}", request.getId());
}
// custom post filter
// 응답의 처리상태코드를 로그로 출력
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if (config.isPostLogger()) {
log.info("Global Filter is end ... status code = {}", response.getStatusCode());
}
}));
};
}
}
filter정보를 application.yml에 저장
# application.yml
server:
port: 8000
spring:
application:
name: apigateway-service
cloud:
gateway:
default-filters:
- name: GlobalFilter
args:
baseMessage: Hello Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
routes:
- id: first-service
predicates:
- Path=/first-service/**
uri: http://localhost:8081
filters:
# - CustomFilter
# - AddRequestHeader=first-request, first-request-header-from-yaml
# - AddResponseHeader=first-response, first-response-header-from-yaml
- id: second-serivce
predicates:
- Path=/second-service/**
uri: http://localhost:8082
filters:
#- CustomFilter
#- AddRequestHeader=second-request, second-request-header-from-yaml
#- AddResponseHeader=second-response, second-response-header-from-yaml
eureka:
client:
register-with-eureka: false
fetch-registry: false
service-url:
defaultZone: http://localhost:8761/eureka
apigateway-serivce 재실행
postman을 이용해서 apigateway-serivce로 check 페이 요청 후 apigateway-service의 로그를 확인
필터 적용 순서
Spring Cloud Gateway - Eureka 연동
기존에 생성한 Eureka 서버인 discovery-service와 apigatewat-service, first-service, second-service를 연동
apigateway-service, first-service, second-service의 pom.xml 파일에 eureka-client 의존성 포함 여부 확인
# porm.xml ... <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> ... |
Eureka 클라이언트를 활성화 → apigateway-service, first-service, second-service의 application.yml
# application.yml ... eureka: client: register-with-eureka: true fetch-registry: true service-url: defaultZone: http://localhost:8761/eureka |
Eureka를 통해서 서비스가 라운팅되도록 apigateway-service의 routes 정보(application.yaml)를 수정
# apigateway-service - application.yml
server:
port: 8000
spring:
application:
name: apigateway-service
cloud:
gateway:
default-filters:
- name: GlobalFilter
args:
baseMessage: Hello Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
routes:
- id: first-service
predicates:
- Path=/first-service/**
uri: lb://MY-FIRST-SERVICE
filters:
- CustomFilter
- id: second-serivce
predicates:
- Path=/second-service/**
uri: lb://MY-SECOND-SERVICE
filters:
- CustomFilter
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
연동 테스트
discovery-service -> apigateway-service -> first/second-service 순으로 실행
인스턴스에 정상적으로 등록되는 것을 확인가능
로드밸런싱 기능
동일한 애플리케이션의 여러 인스턴스로 라우팅이되도록 수정
first-service, second-service에 application.yaml 파일에 랜덤 포트를 설정 → 유레카의 인스턴스 ID를 식별 가능한 형태로 설정
# first-service - application.yml
server:
# port: 8081
port: 0
spring:
application:
name: my-first-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}}
# second-service - application.yml
server:
# port: 8082
port: 0
spring:
application:
name: my-second-service
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
instance:
instance-id: ${spring.application.name}:${spring.application.instance_id:${random.value}}
실행될 여러 인스턴스중 확인을 위해 check()메서드에 현재 인스턴스에 할당된 서비스 포트를 출력하도록 수정(second-service에만 수정)
package com.example.secondservice;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
@Slf4j
@RestController
@RequestMapping("/second-service")
public class SecondServiceController {
...
Environment env;
@Autowired
public SecondServiceController(Environment env) {
this.env = env;
}
...
@GetMapping("/check")
public String check(HttpServletRequest request) {
log.info("check is called in Second Service");
log.info("Server Port from HttpServletRequest: port = {}", request.getServerPort());
log.info("Server Port from Environment: port = {}", env.getProperty("local.server.port"));
return String.format("check is called in Second Service, Server port is %s from HttpServletRequest and %s from Environment", request.getServerPort(), env.getProperty("local.server.port"));
}
}
first/second-service 재기동
second-service는 확인을 위해 2개 이상 기동 -> postman을 이용해 확인
apigateway-service의 포트인 8000으로 접근시 실행중인 second-service의 각각의 포트를 출력
'Spring Cloud' 카테고리의 다른 글
Spring Cloud(MSA) 실습 - 웹 쇼핑몰 3. 주문 서비스 및 테스트 (0) | 2021.09.16 |
---|---|
Spring Cloud(MSA) 실습 - 웹 쇼핑몰 2. 카달로그 서비스 (0) | 2021.09.16 |
Spring Cloud(MSA) 실습 - 웹 쇼핑몰 1. 기본 설정과 회원 서비스 (0) | 2021.09.15 |
댓글