지난 포스팅에서는 Eureka Server와 Microservice들을 등록하는 설정을 알아보았다.
이번 시간에는, Eureka Server에 등록된 서비스들을 Routing하는 설정 방법과 filter를 알아볼 것이다.
0. API Gateway
Spring Cloud Gateway는 받는 요청을 Predicate(조건)에 따라 Filter를 거쳐, 각 Microservice에 Routing을 해주는 역할을 한다.
여기서 Gateway서버는 Spring의 기본 내장 서버인 Tomcat을 사용하지 않고 Netty를 사용하는데 ,Netty는 비동기 이벤트 기반 네트워크 애플리케이션 프레임워크이다.
아무래도 Gateway가 모든 요청들을 받고 Routing하는 역할을 하다보니, 비동기 방식으로 처리하는게 더 빠를 것이다.
1. Gateway Service
Gateway 역할을 해줄 서비스를 구현해 보겠다.
ext {
set('springCloudVersion', "2023.0.0")
}
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
Spring Cloud Gateway 의존성을 추가해주고, 해당 서비스도 Eureka 서버의 Client가 될 것이기 때문에 eureka client 또한 추가해준다.
1-1. yml설정으로 Routing
- application.yml
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE # Load Balancer
predicates:
- Path=/user/**
- id: app-service
uri: lb://APP-SERVICE
predicates:
- Path=/app/**
마찬가지로 해당 서비스 또한 Eureka 서버에 등록하고, application name을 지정해준다.
다음으로, 각 서비스들을 route할 것이다.
현재 나는 user-service와 app-service를 가동중인데, 두 서비스들을 routing 해보겠다.
routes:
- id: user-service
uri: lb://USER-SERVICE # Load Balancer
predicates:
- Path=/user/**
위 설정은 다음과 같다.
1. predicate(조건) : 만약 Request경로가 /user/** 와 같은 형태라면, uri로 이동한다.
2. uri는 loadbalancer(lb)로 넘겨지고, USER-SERVICE로 이름이 등록된 서비스로 이동한다.
해당 서비스 이름은 Eureka 서버에 등록된 이름으로 식별하고, Gateway는 Eureka로 부터 해당 이름을 가진 서비스의 주소를 얻게 된다.
1-2. Class Routing
-application.yml
eureka:
client:
register-with-eureka: true
fetch-registry: true
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: apigateway-service
Gateway 서비스를 등록한다.
- FilterConfig
@Configuration
public class FilterConfig {
@Bean
public RouteLocator gatewayRoutes(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/user/**") //Path 확인
.filters(f -> f.addRequestHeader("User-Request-Header", "User Service Request")
.addResponseHeader("User-Response-Header", "User Service Response")
) //필터 적용
.uri("http://localhost:8082") //uri로 이동
)
.route(r -> r.path("/app/**")
.filters(f -> f.addRequestHeader("App Request Header", "App Service Request")
.addResponseHeader("App Response Header", "App Service Response")
) //필터 적용
.uri("http://localhost:8083")
)
.build();
}
}
위에서 yml파일로 설정했던 항목과 같다.
RouteLocator를 build하는 함수를 Bean으로 등록해주면 된다.
predicate는 .path()메서드로 적용하고, filters()메서드에서는 원하는 필터를 적용시킬 수 있다.
위 예제에서는 Request와 Response Header에 추가해주고 있다.
2. CustomFilter
Filter에는 Pre Filter와 Post Filter가 있다.
사용자의 요청이 들어오면, Pre Filter가 먼저 실행되고, Service를 모두 거친 후 사용자에게 Response를 보내기 전 Post Filter가 적용된다.
각 Filter를 설정하는 방법을 알아보자.
- CustomFilter.Java
@Component
@Slf4j
public class CustomFilter extends AbstractGatewayFilterFactory<CustomFilter.Config> {
public CustomFilter() {
super(Config.class);
}
public static class Config {
//Configuration 정보
}
@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(() -> { //Mono : WebFlux 비동기 방식 서버 단일값 전달
log.info("Custom POST Filter : Response Code : {}", response.getStatusCode());
})
);
});
}
}
AbstractGatewayFilterFactory를 상속한 CustomFilter를 구현할 수 있다.
Filter 내에서 Pre Filter를 구현하고, return시 filter chain내에 Mono클래스를 전달하여 Post Filter를 적용시킬 수 있다.
해당 Filter는 Pre Filter에서는 Request의 Id를 출력하고, Post Filter에서는 Response code를 출력한다.
이제 해당 Custom Filter를 등록해보자.
-application.yml
spring:
application:
name: apigateway-service
cloud:
gateway:
routes:
- id: user-service
uri: lb://USER-SERVICE # Load Balancer
predicates:
- Path=/user/**
filters:
- name : CustomFilter # Custom Filter 등록
- id: app-service
uri: lb://APP-SERVICE
predicates:
- Path=/app/**
Gateway에서, user-service에 방금 만들어 두었던 CustomFilter를 적용시켰다.
3. Global Filter
위는 각 서비스마다 Custom Filter를 적용시키는 방법이다. 그렇다면, 모든 서비스가 거치는 Global Filter는 어떻게 적용시킬까?
- GlobalFilter.java
@Component
@Slf4j
public class GlobalFilter extends AbstractGatewayFilterFactory<GlobalFilter.Config> {
public GlobalFilter() {
super(Config.class);
}
@Data
public static class Config {
//Configuration 정보
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
@Override
public GatewayFilter apply(Config config) {
//Custom PRE Filter
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Global Filter Base Message : {}", config.getBaseMessage());
if (config.isPreLogger()) {
log.info("Global Filter Start : Request Id -> {}", request.getId());
}
//Custom POST Filter
return chain.filter(exchange).then(Mono.fromRunnable(() -> { //Mono : WebFlux 비동기 방식 서버 단일값 전달
if (config.isPostLogger()) {
log.info("Global Filter End : Response Code -> {}", request.getId());
}
})
);
});
}
}
GlobalFilter를 만들었다고 가정해보자. (CustomFilter 만드는 것 처럼 만들면 된다.)
- application.yml
cloud:
gateway:
default-filters:
- name: GlobalFilter
args:
baseMessage : Spring Cloud Gateway Global Filter
preLogger : true
postLogger : true
routes:
- id: user-service
uri: lb://USER-SERVICE # Load Balancer
predicates:
- Path=/user/**
filters:
- name : CustomFilter
- id: app-service
uri: lb://APP-SERVICE
predicates:
- Path=/app/**
default-filters를 만들어둔 GlobalFilter로 설정하여 모든 서비스에 적용되도록 설정했다.
모두 적용하고 실행해보면, 다음과 같이 로그가 나온다.
Global Pre Filter -> Custom Pre Filter -> Service -> Custom Post Filter -> Global Post Filter 순으로 적용된다.
이제 각 필터에 Authentication Filter등 필요한 필터를 적용시키면 되겠다 !
'BackEnd > Spring Cloud' 카테고리의 다른 글
[Spring Cloud] Spring Cloud Config Server 설정값을 Private Repository 에서 가져오기 (0) | 2024.02.12 |
---|---|
[Spring Cloud] Spring Cloud Bus (0) | 2024.02.05 |
[Spring Cloud] Actuator를 이용한 Config Server 기동 (0) | 2024.01.29 |
[Spring Cloud] Eureka Server와 Micro Service 설정 (0) | 2024.01.08 |
[Spring Cloud] Srping Cloud Services (0) | 2024.01.07 |