우리가 이전 포스트들에서 항상 아무생각 없이 override하여 사용했던 apply를 뜯어보자.
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Global PRE baseMessage : {}", config.getBaseMessage());
if(config.isPreLogger()){
log.info("Global Filter Start : request id = {}", request.getId());
}
//custom post filter
return chain.filter(exchange).then(Mono.fromRunnable(()->{
if(config.isPostLogger()){
log.info("Global Filter End : response code = {}", response.getStatusCode());
}
}));
});
}
다음과 같이 exchange와 chain 매개변수를 받아서 람다식으로 풀어서 사용했는데 우리가 사용하는 exchange와 chain은 어디서 오는 것일까?
@Override
public GatewayFilter apply(Config config) {
GatewayFilter filter = new OrderedGatewayFilter();
return filter;
}
우리가 지금까지 람다로 만들어서 return하던 GatewayFilter 객체를 직접 생성하려고 하면 new OrderedGatewayFilter
가 구현체가 되어 GatewayFilter를 생성하여 왔다. 이 OrderedGatewayFilter
의 코드를 살펴보면
위 코드들을 확인할 수 있고 우리가 사용했던 exchange와 chain을 매개변수로 받는 filter mehtod를 확인할 수 있다.
Spring 5.x부터 RxJava(비동기 통신)을 지원하면서 더이상 MVC 패턴이 아닌 WebFlux 기술을 사용한다. WebFlux에서는 Servlet의 Request와 Response를 사용하지 않고 ServerRequest와 ServerResponse 객체를 사용하는데 해당 객체들을 사용하게끔 도와주는 것이 ServerWebExchange 객체이다.
그리고 GatewayFilterchain을 사용하여 Filter들을 연결하는 것에 사용한다.
@Component
@Slf4j
public class LoggingFilter extends AbstractGatewayFilterFactory<LoggingFilter.Config> {
public LoggingFilter() {
super(Config.class);
}
@Data
public static class Config{
private String baseMessage;
private boolean preLogger;
private boolean postLogger;
}
@Override
public GatewayFilter apply(Config config) {
GatewayFilter filter = new OrderedGatewayFilter((exchange, chain)->{
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Logging Filter baseMessage : {}", config.getBaseMessage());
if(config.isPreLogger()){
log.info("Logging PRE Start : request id = {}", request.getId());
}
//custom post filter
return chain.filter(exchange).then(Mono.fromRunnable(()->{
if(config.isPostLogger()){
log.info("Logging POST End : response code = {}", response.getStatusCode());
}
}));
}, Ordered.HIGHEST_PRECEDENCE); //우선순위
return filter;
}
}
filter를 다음과 같이 작성할 수 있다.
그 후에 second service에만 Logging Filter를 적용시켜 보자.
server:
port: 8000
eureka: #eureka 세팅은 현재 사용 안함
client:
fetch-registry: false
register-with-eureka: false
service-url:
defaultZone: http://127.0.0.1:8761/eureka
spring:
application: #gateway service 이름름 name: apigateway-service
cloud:
gateway: #gateway 설정
default-filters:
- name : GlobalFilter #Global Filter로 지정된 java 파일 이름
args:
baseMessage: Spring Cloud Gateway Global Filter
preLogger: true
postLogger: true
routes:
- id: first-service #gateway로 연결될 서비스 이름
uri: http://127.0.0.1:8001/ #gateway로 연결될 서비스 uri
predicates: #gateway로 연결될 서비스의 url 매핑
- Path=/first-service/**
filters:
# - AddRequestHeader=first-request, first-request-header2
# - AddResponseHeader=first-response, first-response-header2
- CustomFilter
- id: second-service
uri: http://127.0.0.1:8002/
predicates:
- Path=/second-service/**
filters:
# - AddRequestHeader=second-request, second-request-header2
# - AddResponseHeader=second-response, second-response-header2
- name: CustomFilter
- name: LoggingFilter
args:
baseMessage: Hi, Logging Filter.
preLogger: true
postLogger: true
전체 코드이다.
first service를 실행한 결과는 이전과 동일하게 출력이된다. 우리가 second service에 설정했으므로 first service에는 전혀 아무런 변경이 없기 때문이다.
하지만 second service는 우리가 설정한대로
Logging -> Global -> Custom 순서로 실행되었다. 이 우선순위를 변경하기 위해서는
@Override
public GatewayFilter apply(Config config) {
GatewayFilter filter = new OrderedGatewayFilter((exchange, chain)->{
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
log.info("Logging Filter baseMessage : {}", config.getBaseMessage());
if(config.isPreLogger()){
log.info("Logging PRE Start : request id = {}", request.getId());
}
//custom post filter
return chain.filter(exchange).then(Mono.fromRunnable(()->{
if(config.isPostLogger()){
log.info("Logging POST End : response code = {}", response.getStatusCode());
}
}));
}, Ordered.LOWEST_PRECEDENCE); //우선순위
return filter;
}
마지막 우선순위를 LOWEST로 변경해준다면
다음과 같이 순서를 변경할 수 있다.