새소식

반응형
Spring/SpringCloudGateway

[SpringCloudGateway] 구성 요소 및 동작 내용

  • -
반응형

overview

Gateway Handler Mapping 

SpringMVC의 동작 구성과 비슷하다. 

DispatcherServlet과 유사하게 Front Controller를 하나두어 진입점을 하나로 통합하였다. 

 

client 호출에서 Gateway Web Handler에 도달하기 전까지의 호출 순서를 보면 아래와 같다 

 

Client ->
HttpWebHandlerAdapter.handle -> (predicate, filter에서 사용하는 ServerWebExchange 생성 및 전달 )
DispatcherHandler.handle -> (DispatcherServlet 유사)(handlerMapping을 찾아 handlerAdapter에서 수행)
RoutePredicateHandlerMapping.getHandlerInternal ->

  DispatcherHandler.handleRequestWith->(webHandler 실행)
FilteringWebHandler.handle (Gateway Filter Chain)

 

DispatcherHandler

	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		if (this.handlerMappings == null) {
			return createNotFoundError();
		}
		if (CorsUtils.isPreFlightRequest(exchange.getRequest())) {
			return handlePreFlight(exchange);
		}
		return Flux.fromIterable(this.handlerMappings)
				.concatMap(mapping -> mapping.getHandler(exchange))
				.next()
				.switchIfEmpty(createNotFoundError())
				.onErrorResume(ex -> handleDispatchError(exchange, ex))
				.flatMap(handler -> handleRequestWith(exchange, handler));
	}

 

요청(exchange)을 적합하게 처리할 handlerMapping을 찾는다 -> RoutePredicateHandlerMapping

  • concatMap : flux를 single flux로 전환하여 실행, 다만 순차적으로 ( <-> flatMap)
  • next : Emit only the first item emitted by this Flux

RoutePredicateHandlerMapping

  • yml에 등록된 route들 중에 predicate가 true인 타겟을 찾아, exchange의 attribute에 저장
    •  추후에 web handler에서 꺼내서 사용 
	protected Mono<Route> lookupRoute(ServerWebExchange exchange) {
		return this.routeLocator.getRoutes()
				// individually filter routes so that filterWhen error delaying is not a
				// problem
				.concatMap(route -> Mono.just(route).filterWhen(r -> {
					// add the current route we are testing
					exchange.getAttributes().put(GATEWAY_PREDICATE_ROUTE_ATTR, r.getId());
					return r.getPredicate().apply(exchange);
				})
				.next()
				.map(route -> {
					if (logger.isDebugEnabled()) {
						logger.debug("Route matched: " + route.getId());
					}
					validateRoute(route, exchange);
					return route;
				});
	}

 

Gateway Web Handler 

 

FilteringWebHandler

	@Override
	public Mono<Void> handle(ServerWebExchange exchange) {
		Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);
		List<GatewayFilter> gatewayFilters = route.getFilters();

		List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);
		combined.addAll(gatewayFilters);
		// TODO: needed or cached?
		AnnotationAwareOrderComparator.sort(combined);

		if (logger.isDebugEnabled()) {
			logger.debug("Sorted gatewayFilterFactories: " + combined);
		}

		return new DefaultGatewayFilterChain(combined).filter(exchange);
	}

 

filter list들의 order로 순서를 지정한다.

application.yml로 등록한 경우 위에 정의될수록 우선순위가 높아진다. 

우선순위가 같은 경우 globalFilter가 route에 정의된 필터보다 먼저 수행된다. 

 

 

NettyRoutingFilter : remote api 호출

NettyWriteResponseFilter: 응답을 exchange response에 매핑 

 

필터의 경우 pre, post로 나뉘어서 정의한 내용에 맞게 동작한다. 

 

pre 

    @Override
    public GatewayFilter apply(Config config) {

        return (exchange, chain) -> {
            HttpHeaders headers = exchange.getRequest().getHeaders();
            // .. 
            return chain.filter(exchange.mutate().request(request).build());
        };
    }

 

post

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            return chain.filter(exchange)
                        .then(Mono.fromRunnable(() -> {
                            // post logic 
                        }));
        };
    }
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.