저번 Spring Cloud Gateway 개념에 이어서 이번엔 간단하게 구현해보고 테스트까지 해보려고 합니다.
그리고 오타 찾기 하지마시고 붙여넣기 하셔도 돼요.
구현해보고 테스트해보는 과정이 중요한 것 같습니다.
1. 프로젝트를 하나 생성해볼게요
프로젝트명은 자유, java 버전은 17, Maven
스프링 부트 버전은 3.4.0, 의존성은 Lombok, Eureka Discovery Client, Reactive Gateway 추가
2. 프로젝트 생성 후 filter패키지를 생성하고 GlobalFilter 클래스를 아래처럼 생성해줍니다.
package com.example.demo.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);
}
public GatewayFilter apply(Config config) {
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 Start: request id -> {}", request.getId());
}
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
if (config.isPostLogger()) {
log.info("Global Filter End: response code -> {}", response.getStatusCode());
}
}));
}));
}
}
3. filter패키지에 CustomFilter 클래스를 아래처럼 생성해줍니다.
package com.example.demo.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;
@Slf4j
@Component
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
public static class Config {
}
public CustomFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
System.out.println("Custom PRE filter: request id -> " + request.getId());
return chain.filter(exchange).then(Mono.fromRunnable(() -> {
System.out.println("Custom POST filter: response code ->" + response.getStatusCode());
}));
});
}
}
4. src/main/resourcecs/application.properties 의 이름을 application.yml 로 변경하고 아래 내용을 넣습니다.
server:
port: 8000
spring:
application:
name: api-gateway-1
cloud:
gateway:
routes:
- id: service1
uri: lb://service1
predicates:
- Path=/service1/**
filters:
- CustomFilter
- id: service2
uri: lb://service2
predicates:
- Path=/service2/**
filters:
- AddRequestHeader=second-request, second-request-header
- AddResponseHeader=second-response, second-response-header
default-filters:
- name: GlobalFilter
args:
baseMessage: Spring Cloud Gateway GlobalFilter
preLogger: true
postLogger: true
management:
endpoints:
web:
exposure:
include:
- "gateway"
endpoint:
gateway:
enabled: true
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
간단히 설명하면, api gateway 포트는 8000으로 설정하고,
Gateway는 service1, service2 라는 마이크로서비스를 라우팅 대상으로 설정합니다.(id: service1..)
service1과, service2는 각각의 서비스 이름으로 Eureka 서비스 레지스트리에 등록해야되는데 이건 밑에 쓰겠습니다.
그리고 Path=/service1/**의 요청은 service1 으로, Path/=service2/**의 요청은 service2로 전달합니다.
service1 에서 filters: - CustomFilter 이부분은 service1에만 요청 전/후로 처리를 하게끔 설정합니다.(위에서 CustomFilter 만들었죠?)
service2 에서 filters : - AddRequestHeader=second-request, second-request-header, AddResponseHeader... 이부분은
필터를 통해서 요청헤더와 응답헤더를 추가한다는 뜻입니다.
그리고 GlobalFilter는 모든 라우팅 요청에 대해서 필터를 적용한다는 뜻이고, baseMessage, preLogger, postLogger 설정으로 로깅 및 전/후 공통처리 작업을 하도록 설정한다는 뜻입니다.
그리고 application.yml에서 아래부분은 Eureka와의 연동 설정입니다.
지금 만들고 있는 api gateway는 Eureka의 클라이언트로 등록되고(client: register-with-eureka: true)
서비스 레지스트리 정보를 가져옵니다. 어떤 의미냐면 어떤 서비스가 유레카에 저장되어있는지 목록을 조회할 수 있게끔 합니다. (client: fetch-registry: true)
(위에서 프로젝트 생성할때 의존성에 Eureka Client를 넣은 이유입니다.)
defaultZone: http://localhost:8761/eureka 라고 되어있는 부분은
Eureka Server를 http://localhost:8761 에서 실행시키겠다라는 뜻입니다.
5. 이대로 gateway만 실행시키면 실행되지 않습니다. 등록되어 있는 Eureka server를 먼저 실행시켜야 해요.
간단하게 Eureka server 생성 ㄱㄱ (5분도 안걸림)
의존성에는 Eureka Server 한개만.
6. @EnableEurekaServer 추가
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
7. application.yml
server:
port: 8761
spring:
application:
name: eureka-discovery-service
eureka:
client:
register-with-eureka: false # eureka server를 registry에 등록할지 여부
fetch-registry: false # registry에 있는 정보들을 가져올지 여부
8. Eureka 서버 실행시키고, localhost:8761 접속하시면 아래처럼 대시보드가 뜹니다!
9. 이제 아까 생성했던 api-gateway server를 실행시킵니다.
그리고 대시보드(localhost:8761)에서 새로고침하면 API-GATE-WAY-1 이 보이시죠!
그럼 이제 API GATEWAY 플랫폼 그림에서 GATEWAY, Eureka Server 부분(파란색으로 칠한 부분)이 완성됐습니다.
글이 너무 길어져서 다음 글에서 계속 정리해보겠습니다.
다음 글에서 할 일은 Eureka Client(보라색으로 칠한 부분) 를 몇개 생성해서 Eureka Client로 등록하고
Gateway로 요청해서 라우팅되는 것까지 테스트 해보는 것입니다.
끝.
bye bye~~
'공부내용 정리 > 스프링' 카테고리의 다른 글
[SpringBoot] Log 남길 때 혼나지 않기 (0) | 2025.01.09 |
---|---|
[SpringBoot, MSA #4] Eureka Client 등록 및 Route (2) | 2024.12.19 |
[SpringBoot, MSA #2] Spring Cloud Gateway, 스프링 클라우드 게이트웨이 개념 (2) | 2024.12.16 |
[SpringBoot, MSA #1] 마이크로서비스 아키텍쳐, MSA란? (2) | 2024.12.16 |
Front Controller Pattern (3) | 2023.10.16 |