spring cloud gateway 启动流程及原理分析

扫码关注公众号:Java 技术驿站

发送:vip
将链接复制到本浏览器,永久解锁本站全部文章

【公众号:Java 技术驿站】 【加作者微信交流技术,拉技术群】
免费领取 2000+ 道 Java 面试题

spring cloud gateway 作为新一代的微服务网关已经发布了一段时间,我从7月份开始使用到现在已经4个月了。但是我一直处于一种只会使用,原理一知半解的水平。我们小组作为公司微服务产品的实践者,我自己作为组中一员完成了spring cloud gateway的开发,也解决了很多棘手的问题,却对它的原理和启动流程一知半解,好几次就是因为不了解它的启动流程,导致开发受挫,进度缓慢。现在正值闲时,正好看一下相关的源码,理解他的启动流程。本文基于spring cloud Finchley.RELEASE版本,最新的SR2版本一些内容有改变,但总体改变不大。

首先是网关的包结构
20191123100187\_1.png

其中actuate中定义了一个叫GatewayControllerEndpoint的类,这个类提供一些对外的接口,可以获取网关的一些信息,比如路由的信息,改变路由地址等等。

config中定义了一些启动时去加载的类,配置路由信息和读取你的配置文件就在这里完成。

discovery中定义了注册中心相关的内容,包括注册中心的路由等。

event定义了一些事件他们都继承自ApplicationEvent,对事件发布不了解的可以去看看spring的代码。

filter中定义了spring cloud gateway实现的一些过滤器。

handler中定义了很多Predicate相关的Factory

route就是我们路由的相关

support是工具包等。

下面就是gateway启动流程的分析了

config包

20191123100187\_2.png

网关启动第一步加载的就是去加载config包下的几个类。

20191123100187\_3.png

这几个类就定义了网关需要加载的配置项。

在我第一次做网关开发的时候我引入了spring-boot-starter-web的依赖,这样是会报错的,因为gateway是基于spring-webflux开发的,他依赖的DispatcherHandler就和我们web里的DispatcherServlet一样的功能。

这里的GatewayClassPathWarningAutoConfiguration这个类,就指明了我们需要什么不需要什么,他加载于GatewayAutoConfiguration之前,如果DispatcherServlet存在,就会给与警告,同样的DispatcherHandler不存在也会警告。


    @Configuration

    @AutoConfigureBefore(GatewayAutoConfiguration.class)

    public class GatewayClassPathWarningAutoConfiguration {

     private static final Log log = LogFactory.getLog(GatewayClassPathWarningAutoConfiguration.class);

     private static final String BORDER = "\n\n**********************************************************\n\n";

     @Configuration

     @ConditionalOnClass(name = "org.springframework.web.servlet.DispatcherServlet")

     protected static class SpringMvcFoundOnClasspathConfiguration {

      public SpringMvcFoundOnClasspathConfiguration() {

       log.warn(BORDER+"Spring MVC found on classpath, which is incompatible with Spring Cloud Gateway at this time. "+

         "Please remove spring-boot-starter-web dependency."+BORDER);

      }

     }

     @Configuration

     @ConditionalOnMissingClass("org.springframework.web.reactive.DispatcherHandler")

     protected static class WebfluxMissingFromClasspathConfiguration {

      public WebfluxMissingFromClasspathConfiguration() {

       log.warn(BORDER+"Spring Webflux is missing from the classpath, which is required for Spring Cloud Gateway at this time. "+

         "Please add spring-boot-starter-webflux dependency."+BORDER);

      }

     }

    }

它加载完成之后加载的是GatewayLoadBalancerClientAutoConfiguration这个是gateway负载均衡的过滤器实现的加载,他将LoadBalancerClientFilter 注入到了容器中,这个过滤器后面再说。


    @Configuration

    @ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})

    @AutoConfigureAfter(RibbonAutoConfiguration.class)

    public class GatewayLoadBalancerClientAutoConfiguration {

     // GlobalFilter beans

     @Bean

     @ConditionalOnBean(LoadBalancerClient.class)

     public LoadBalancerClientFilter loadBalancerClientFilter(LoadBalancerClient client) {

      return new LoadBalancerClientFilter(client);

     }

    }

之后便是我们的GatewayAutoConfiguration正式加载了,这个里面定义了非常多的内容,我们大部分用到的过滤器,过滤器工厂都是在这里构建的。包括之前的gatewayControllerEndpoint也是在这里注入容器中的。这个类的定义很长,我就不再这里都放了,列举几个。


    @Configuration

    //开启网关,不写默认为true

    @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)

    @EnableConfigurationProperties

    @AutoConfigureBefore(HttpHandlerAutoConfiguration.class)

    @AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})

    @ConditionalOnClass(DispatcherHandler.class)

    public class GatewayAutoConfiguration {

     @Configuration

     @ConditionalOnClass(HttpClient.class)

     protected static class NettyConfiguration {

      @Bean

      @ConditionalOnMissingBean

      public HttpClient httpClient(@Qualifier("nettyClientOptions") Consumer<? super HttpClientOptions.Builder> options) {

       return HttpClient.create(options);

      }

      ... //还有很多 这里不列举了。我们都知道spring cloud 是基于Netty实现的,这里他这个静态内部类就是初始化netty需要的东西。

    }

    //初始化了加载配置文件的对象,建立route

    @Bean

     public GatewayProperties gatewayProperties() {

      return new GatewayProperties();

     }

    //初始化请求转发 过滤器

    @Bean

     @ConditionalOnProperty(name = "spring.cloud.gateway.forwarded.enabled", matchIfMissing = true)

     public ForwardedHeadersFilter forwardedHeadersFilter() {

      return new ForwardedHeadersFilter();

     }

     //最后初始化gatewayControllerEndpoint 这里注意只有引入spring-boot-starter-actuator他才会加载

    @Configuration

     @ConditionalOnClass(Health.class)

     protected static class GatewayActuatorConfiguration {

      @Bean

      @ConditionalOnEnabledEndpoint

      public GatewayControllerEndpoint gatewayControllerEndpoint(RouteDefinitionLocator routeDefinitionLocator, List<GlobalFilter> globalFilters,

                    List<GatewayFilterFactory> GatewayFilters, RouteDefinitionWriter routeDefinitionWriter,

                    RouteLocator routeLocator) {

       return new GatewayControllerEndpoint(routeDefinitionLocator, globalFilters, GatewayFilters, routeDefinitionWriter, routeLocator);

      }

     }

这里注意我们通过注册中心发现的路由不是在config包下定义的而是在discovery包下GatewayDiscoveryClientAutoConfiguration实现了从注册中心发现内容


    @Configuration

    @ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)

    @AutoConfigureBefore(GatewayAutoConfiguration.class)

    @ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})

    @EnableConfigurationProperties

    public class GatewayDiscoveryClientAutoConfiguration {

     @Bean

     @ConditionalOnBean(DiscoveryClient.class)

     @ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")

     public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(

       DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {

      return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);

     }

     @Bean public DiscoveryLocatorProperties discoveryLocatorProperties() {

      DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();

      properties.setPredicates(initPredicates());

      properties.setFilters(initFilters());

      return properties;

     }

    }

这些注册完毕后,我们的配置文件就开始读取了,

20191123100187\_4.png

这两个中定义了我们配置文件的读取规则,其中DiscoveryLocatorProperties都有默认的值,我们可以不用关心。GatewayProperties比较重要


    @ConfigurationProperties("spring.cloud.gateway")

    @Validated

    public class GatewayProperties {

     @NotNull

     @Valid

     private List<RouteDefinition> routes = new ArrayList<>();

     /** * List of filter definitions that are applied to every route. */

     private List<FilterDefinition> defaultFilters = new ArrayList<>();

     private List<MediaType> streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM,

       MediaType.APPLICATION_STREAM_JSON);

    }

这里就定义了我们配置文件里的所有路由信息,读取完成后,接下来就要变成真正的路由信息了。

这里就要说一下 RouteLocator接口,这个接口提供了一个getRoutes()方法返回一个Flux所以,他的实现中就定义了读取配置文件转成路由的关键。


    public interface RouteLocator {

     Flux<Route> getRoutes();

    }

我们先看从配置文件中加载的路由信息也就是他的实现RouteDefinitionRouteLocator


    public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {

     protected final Log logger = LogFactory.getLog(getClass());

     private final RouteDefinitionLocator routeDefinitionLocator;

     private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();

     private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();

     private final GatewayProperties gatewayProperties;

     private final SpelExpressionParser parser = new SpelExpressionParser();

     private BeanFactory beanFactory;

     private ApplicationEventPublisher publisher;

     public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator,

                List<RoutePredicateFactory> predicates,

                List<GatewayFilterFactory> gatewayFilterFactories,

                GatewayProperties gatewayProperties) {

      this.routeDefinitionLocator = routeDefinitionLocator;

      initFactories(predicates);

      gatewayFilterFactories.forEach(factory -> this.gatewayFilterFactories.put(factory.name(), factory));

      this.gatewayProperties = gatewayProperties;

     }

      ...

    }

我们定位到他的构造方法,debug启动

20191123100187\_5.png

发现这个类的一个属性routeDefinitionLocator中已经定义了我们的路由,只不过是代理对象。 这个属性所对应的接口RouteDefinitionLocator有很多种实现

20191123100187\_6.png

我们现在看PropertiesRouteDefinitionLocator,这里


    public class PropertiesRouteDefinitionLocator implements RouteDefinitionLocator {

     private final GatewayProperties properties;

     public PropertiesRouteDefinitionLocator(GatewayProperties properties) {

      this.properties = properties;

     }

     @Override

     public Flux<RouteDefinition> getRouteDefinitions() {

      return Flux.fromIterable(this.properties.getRoutes());

     }

    }

他的构造方法读取了GatewayProperties ,所以到这里我们的路由就已经存在了。通过他的getRoutes()方法,我们就能方便的取出所有定义的路由信息了

而他的getRoutes()方法又是这样定义的


    @Override

     public Flux<Route> getRoutes() {

      return this.routeDefinitionLocator.getRouteDefinitions()

        .map(this::convertToRoute)

        //TODO: error handling

        .map(route -> {

         if (logger.isDebugEnabled()) {

          logger.debug("RouteDefinition matched: " + route.getId());

         }

         return route;

        });

     }

routeDefinitionLocator.getRouteDefinitions()返回从配置文件中读取的路由转换成 Flux 再通过convertToRoute转换成路由对象的数组,封装成Flux()至此,配置文件中读取路由信息就结束了。

接下来我们来解释通过注册中心的方式接受的路由信息。这里由一个叫DiscoveryClientRouteDefinitionLocator的类来实现,他同样实现了RouteDefinitionLocator接口,能够返回Flux


    public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {

     private final DiscoveryClient discoveryClient;

     private final DiscoveryLocatorProperties properties;

     private final String routeIdPrefix;

     public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {

    // 服务发现信息 

      this.discoveryClient = discoveryClient;

     //这个配置是前面说过的DiscoveryLocatorProperties

      this.properties = properties;

      if (StringUtils.hasText(properties.getRouteIdPrefix())) {

       this.routeIdPrefix = properties.getRouteIdPrefix();

      } else {

       this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";

      }

     }

     //这个是核心

     @Override

     public Flux<RouteDefinition> getRouteDefinitions() {

      SimpleEvaluationContext evalCtxt = SimpleEvaluationContext

        .forReadOnlyDataBinding()

        .withInstanceMethods()

        .build();

      SpelExpressionParser parser = new SpelExpressionParser();

      Expression includeExpr = parser.parseExpression(properties.getIncludeExpression());

      Expression urlExpr = parser.parseExpression(properties.getUrlExpression());

      return Flux.fromIterable(discoveryClient.getServices())

        .map(discoveryClient::getInstances)

        .filter(instances -> !instances.isEmpty())

        .map(instances -> instances.get(0))

        .filter(instance -> {

         Boolean include = includeExpr.getValue(evalCtxt, instance, Boolean.class);

         if (include == null) {

          return false;

         }

         return include;

        })

        .map(instance -> {

         String serviceId = instance.getServiceId();

                        RouteDefinition routeDefinition = new RouteDefinition();

                        routeDefinition.setId(this.routeIdPrefix + serviceId);

         String uri = urlExpr.getValue(evalCtxt, instance, String.class);

         routeDefinition.setUri(URI.create(uri));

         final ServiceInstance instanceForEval = new DelegatingServiceInstance(instance, properties);

         for (PredicateDefinition original : this.properties.getPredicates()) {

          PredicateDefinition predicate = new PredicateDefinition();

          predicate.setName(original.getName());

          for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {

           String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);

           predicate.addArg(entry.getKey(), value);

          }

          routeDefinition.getPredicates().add(predicate);

         }

                        for (FilterDefinition original : this.properties.getFilters()) {

                         FilterDefinition filter = new FilterDefinition();

                         filter.setName(original.getName());

          for (Map.Entry<String, String> entry : original.getArgs().entrySet()) {

           String value = getValueFromExpr(evalCtxt, parser, instanceForEval, entry);

           filter.addArg(entry.getKey(), value);

          }

          routeDefinition.getFilters().add(filter);

         }

                        return routeDefinition;

        });

     }

当我们调用到getRouteDefinitions的时候,他通过discoveryClient转换出了服务发现中心的服务路由

20191123100187\_7.png

注意这里他没有被转换为Flux而是保留为Flux 这是一个坑,我们前期很多时候去找Route发现根本就没有从服务注册中心拉下来的,现在才知道,他压根就没去转。

到这里,我们的路由信息就加载完毕了,网关也就启动完成了,之后就是发送请求过滤器发功的时候了。

我们第一个关注的类就是DispatcherHandler,这个类提供的handle()方法,封装了我们之后所有的handlerMappings


    public class DispatcherHandler implements WebHandler, ApplicationContextAware {

     ...

     @Override

     public Mono<Void> handle(ServerWebExchange exchange) {

      if (logger.isDebugEnabled()) {

       ServerHttpRequest request = exchange.getRequest();

       logger.debug("Processing " + request.getMethodValue() + " request for [" + request.getURI() + "]");

      }

      if (this.handlerMappings == null) {

       return Mono.error(HANDLER_NOT_FOUND_EXCEPTION);

      }

      return Flux.fromIterable(this.handlerMappings)

        .concatMap(mapping -> mapping.getHandler(exchange))

        .next()

        .switchIfEmpty(Mono.error(HANDLER_NOT_FOUND_EXCEPTION))

        .flatMap(handler -> invokeHandler(exchange, handler))

        .flatMap(result -> handleResult(exchange, result));

     }

    ...

    }

这里会真正的调用我们前面注册的route 的那些 getRouteDefinitions()方法,具体的我也没看明白,大概就是封装了这些Mapping进入之后的过滤链中

20191123100187\_8.png

之后就到了FilteringWebHandler类,他的handler方法封装了过滤器进去


    @Override

     public Mono<Void> handle(ServerWebExchange exchange) {

      //h获取到当前访问的路由对象

      Route route = exchange.getRequiredAttribute(GATEWAY_ROUTE_ATTR);

      //获取当前已经存在的 过滤器 也就是配置的默认过滤器

      List<GatewayFilter> gatewayFilters = route.getFilters();

     //获取全局过滤器

      List<GatewayFilter> combined = new ArrayList<>(this.globalFilters);

      combined.addAll(gatewayFilters);

      //按order排序

      AnnotationAwareOrderComparator.sort(combined);

      logger.debug("Sorted gatewayFilterFactories: "+ combined);

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

     }

这里的全局过滤器包括除了我标记的两个以外的所有过滤器,之后再介绍

20191123100187\_9.png

最后按照order排序后的过滤器顺序为

20191123100187\_10.png

之后就真正的开始进入过滤链了 排除掉我们自己实现的过滤器 第一个进入的是AdaptCachedBodyGlobalFilter

他用来缓存我们的requestBody


    @Override

     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

      Flux<DataBuffer> body = exchange.getAttributeOrDefault(CACHED_REQUEST_BODY_KEY, null);

      if (body != null) {

      //封装 ServerHttpRequest 使得requestBody 能够复写

       ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {

        @Override

        public Flux<DataBuffer> getBody() {

         return body;

        }

       };

       return chain.filter(exchange.mutate().request(decorator).build());

      }

      return chain.filter(exchange);

     }

然后进入的是NettyWriteResponseFilter 这个过滤器实现的是返回response 也就是请求完成后返回的对象。他这里巧妙的使用then()


    @Override

     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

      // NOTICE: nothing in "pre" filter stage as CLIENT_RESPONSE_ATTR is not added

      // then 当filter完成后执行,也就是过滤链执行完毕,返回结果的时候

      return chain.filter(exchange).then(Mono.defer(() -> {

       HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR);

       if (clientResponse == null) {

        return Mono.empty();

       }

       log.trace("NettyWriteResponseFilter start");

       ServerHttpResponse response = exchange.getResponse();

       NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory();

       //TODO: what if it's not netty

       final Flux<NettyDataBuffer> body = clientResponse.receive()

         .retain() //TODO: needed?

         .map(factory::wrap);

       MediaType contentType = response.getHeaders().getContentType();

       return (isStreamingMediaType(contentType) ?

         response.writeAndFlushWith(body.map(Flux::just)) : response.writeWith(body));

      }));

     }

后面就是返回结果了 没什么可说的。之后的过滤器我就不一个一个说了,讲讲比较重要的。

RouteToRequestUrlFilter我在注释上标明了,当前uri的值


    @Override

     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

      Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR);

      if (route == null) {

       return chain.filter(exchange);

      }

      log.trace("RouteToRequestUrlFilter start");\

      // http://localhost:8804/e6Organization/getOrgTreeList

      URI uri = exchange.getRequest().getURI();

      boolean encoded = containsEncodedParts(uri);

      // lb://BASE-API-WEB

      URI routeUri = route.getUri();

      if (hasAnotherScheme(routeUri)) {

       // this is a special url, save scheme to special attribute

       // replace routeUri with schemeSpecificPart

       exchange.getAttributes().put(GATEWAY_SCHEME_PREFIX_ATTR, routeUri.getScheme());

       routeUri = URI.create(routeUri.getSchemeSpecificPart());

      }

      // lb://BASE-API-WEB:8804/e6Organization/getOrgTreeList

      URI requestUrl = UriComponentsBuilder.fromUri(uri)

        .uri(routeUri)

        .build(encoded)

        .toUri();

      exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);

      return chain.filter(exchange);

     }

最后他将url拼装成了我们需要的,能够做服务发现的url,这时他就会进入LoadBalancerClientFilter 同样我标注url的变化


    @Override

     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

      // lb://BASE-API-WEB:8804/e6Organization/getOrgTreeList 刚才我们封装完毕的url

      URI url = exchange.getAttribute(GATEWAY_REQUEST_URL_ATTR);

      String schemePrefix = exchange.getAttribute(GATEWAY_SCHEME_PREFIX_ATTR);

      if (url == null || (!"lb".equals(url.getScheme()) && !"lb".equals(schemePrefix))) {

       return chain.filter(exchange);

      }

      //preserve the original url

      addOriginalRequestUrl(exchange, url);

      log.trace("LoadBalancerClientFilter url before: " + url);

      // RibbonServer{serviceId='BASE-API-WEB', server=192.168.47.1:12993, secure=false, metadata={}}

      final ServiceInstance instance = loadBalancer.choose(url.getHost());

      if (instance == null) {

       throw new NotFoundException("Unable to find instance for " + url.getHost());

      }

      // http://localhost:8804/e6Organization/getOrgTreeList

      URI uri = exchange.getRequest().getURI();

      // if the `lb:<scheme>` mechanism was used, use `<scheme>` as the default,

      // if the loadbalancer doesn't provide one.

      String overrideScheme = null;

      if (schemePrefix != null) {

       overrideScheme = url.getScheme();

      }

      // http://192.168.47.1:12993/e6Organization/getOrgTreeList 到这时 这个地址已经是正确的访问地址了。

      URI requestUrl = loadBalancer.reconstructURI(new DelegatingServiceInstance(instance, overrideScheme), uri);

      log.trace("LoadBalancerClientFilter url chosen: " + requestUrl);

      exchange.getAttributes().put(GATEWAY_REQUEST_URL_ATTR, requestUrl);

      return chain.filter(exchange);

     }

最后进入NettyRoutingFilter 这个filter真正做请求的发送,他使用HttpClient进行请求的发送。这个类不是很长 我就都拷过来


    public class NettyRoutingFilter implements GlobalFilter, Ordered {

     private final HttpClient httpClient;

     private final ObjectProvider<List<HttpHeadersFilter>> headersFilters;

     public NettyRoutingFilter(HttpClient httpClient,

       ObjectProvider<List<HttpHeadersFilter>> headersFilters) {

      this.httpClient = httpClient;

      this.headersFilters = headersFilters;

     }

     @Override

     public int getOrder() {

      return Ordered.LOWEST_PRECEDENCE;

     }

     @Override

     public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { 

    // http://192.168.47.1:12993/e6Organization/getOrgTreeList 我们刚才处理好的url

      URI requestUrl = exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR);

      String scheme = requestUrl.getScheme(); 

      //必须是 http 或者 https 和没有被路由

      if (isAlreadyRouted(exchange) || (!"http".equals(scheme) && !"https".equals(scheme))) {

       return chain.filter(exchange);

      }

     // 设置为已经路由,防止请求重复路由

      setAlreadyRouted(exchange);

      ServerHttpRequest request = exchange.getRequest();

      final HttpMethod method = HttpMethod.valueOf(request.getMethod().toString());

      final String url = requestUrl.toString();

      HttpHeaders filtered = filterRequest(this.headersFilters.getIfAvailable(),

        exchange);

      final DefaultHttpHeaders httpHeaders = new DefaultHttpHeaders();

      filtered.forEach(httpHeaders::set);

      String transferEncoding = request.getHeaders().getFirst(HttpHeaders.TRANSFER_ENCODING);

      boolean chunkedTransfer = "chunked".equalsIgnoreCase(transferEncoding);

      boolean preserveHost = exchange.getAttributeOrDefault(PRESERVE_HOST_HEADER_ATTRIBUTE, false);

     //到这里发送http请求

      return this.httpClient.request(method, url, req -> {

       final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach)

         .headers(httpHeaders)

         .chunkedTransfer(chunkedTransfer)

         .failOnServerError(false)

         .failOnClientError(false);

       if (preserveHost) {

        String host = request.getHeaders().getFirst(HttpHeaders.HOST);

        proxyRequest.header(HttpHeaders.HOST, host);

       }

       return proxyRequest.sendHeaders() //I shouldn't need this

         .send(request.getBody().map(dataBuffer ->

           ((NettyDataBuffer)dataBuffer).getNativeBuffer()));

      }).doOnNext(res -> { //接受请求返回结果

       ServerHttpResponse response = exchange.getResponse();

       // put headers and status so filters can modify the response

       HttpHeaders headers = new HttpHeaders();

       res.responseHeaders().forEach(entry -> headers.add(entry.getKey(), entry.getValue()));

    // 这里可能导致空指针 是我用的版本的bug SR2版本已经解决 

       exchange.getAttributes().put("original_response_content_type", headers.getContentType());

       HttpHeaders filteredResponseHeaders = HttpHeadersFilter.filter(

         this.headersFilters.getIfAvailable(), headers, exchange, Type.RESPONSE);

       response.getHeaders().putAll(filteredResponseHeaders);

       HttpStatus status = HttpStatus.resolve(res.status().code());

       if (status != null) {

        response.setStatusCode(status);

       } else if (response instanceof AbstractServerHttpResponse) {

        // https://jira.spring.io/browse/SPR-16748

        ((AbstractServerHttpResponse) response).setStatusCodeValue(res.status().code());

       } else {

        throw new IllegalStateException("Unable to set status code on response: " +res.status().code()+", "+response.getClass());

       }

       // Defer committing the response until all route filters have run

       // Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter

       exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res);

      }).then(chain.filter(exchange));

     }

    }

当这步执行完之后,可以理解为先前的NettyWriteResponseFilter 的then()开始执行,最终返回请求结果。至此spring cloud gateway 的启动流程和访问流程就结束了。


来源:http://ddrv.cn/a/88268

赞(0) 打赏
版权归原创作者所有,任何形式的转载请联系博主:daming_90:Java 技术驿站 » spring cloud gateway 启动流程及原理分析

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏