006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载、Route初始化加载

一、GatewayProperties

1.1、在GatewayAutoConfiguration中加载

  在Spring-Cloud-Gateway初始化时,同时GatewayAutoConfiguration核心配置类会被初始化加载如下 :

NettyConfiguration 底层通信netty配置
GlobalFilter (AdaptCachedBodyGlobalFilter,RouteToRequestUrlFilter,ForwardRoutingFilter,ForwardPathFilter,WebsocketRoutingFilter,WeightCalculatorWebFilter等)
FilteringWebHandler
GatewayProperties
PrefixPathGatewayFilterFactory
RoutePredicateFactory
RouteDefinitionLocator
RouteLocator
RoutePredicateHandlerMapping 查找匹配到 Route并进行处理
GatewayWebfluxEndpoint 管理网关的 HTTP API

  其中在GatewayAutoConfiguration配置加载中含初始化加载GatewayProperties实例的配置:

查看GatewayAutoConfiguration源码:

    @Bean
    public GatewayProperties gatewayProperties() {
        return new GatewayProperties();
    }

1.2、再次查看GatewayProperties源码:

@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {
    @NotNull
    @Valid
    private List<RouteDefinition> routes = new ArrayList();
    private List<FilterDefinition> defaultFilters = new ArrayList();
    private List<MediaType> streamingMediaTypes;

    public GatewayProperties() {
        this.streamingMediaTypes = Arrays.asList(MediaType.TEXT_EVENT_STREAM, MediaType.APPLICATION_STREAM_JSON);
    }

    public List<RouteDefinition> getRoutes() {
        return this.routes;
    }

    public void setRoutes(List<RouteDefinition> routes) {
        this.routes = routes;
    }

    public List<FilterDefinition> getDefaultFilters() {
        return this.defaultFilters;
    }

    public void setDefaultFilters(List<FilterDefinition> defaultFilters) {
        this.defaultFilters = defaultFilters;
    }

    public List<MediaType> getStreamingMediaTypes() {
        return this.streamingMediaTypes;
    }

    public void setStreamingMediaTypes(List<MediaType> streamingMediaTypes) {
        this.streamingMediaTypes = streamingMediaTypes;
    }

    public String toString() {
        return "GatewayProperties{routes=" + this.routes + ", defaultFilters=" + this.defaultFilters + ", streamingMediaTypes=" + this.streamingMediaTypes + ‘}‘;
    }
}

以上会被默认加载并且读取配置信息,如下配置信息:

  • spring.cloud.gateway.routes:网关路由定义配置,列表形式
  • spring.cloud.gateway.default-filters: 网关默认过滤器定义配置,列表形式
  • spring.cloud.gateway.streamingMediaTypes:网关网络媒体类型,列表形式

其中routes是RouteDefinition集合,defaultFilters是FilterDefinition集合,参看具体的配置字段。实际配置文件可如下:

spring:
  cloud:
    gateway:
      default-filters:
      - PrefixPath=/httpbin
      - AddResponseHeader=X-Response-Default-Foo, Default-Bar
      routes:
      - id: websocket_test
        uri: ws://localhost:9000
        order: 9000
        predicates:
        - Path=/echo
      - id: default_path_to_httpbin
        uri: ${test.uri}
        order: 10000
        predicates:
        - Path=/**

注意:default-filters的配置PrefixPath=/httpbin字符串,可以查看FilterDefinition的构造函数,它其中构造函数包含接收一个text字符串解析字符传并创建实例信息。predicates的配置也是如此。

字符传格式:name=param1,param2,param3

    public FilterDefinition(String text) {
        int eqIdx = text.indexOf("=");
        if (eqIdx <= 0) {
            this.setName(text);
        } else {
            this.setName(text.substring(0, eqIdx));
            String[] args = StringUtils.tokenizeToStringArray(text.substring(eqIdx + 1), ",");

            for(int i = 0; i < args.length; ++i) {
                this.args.put(NameUtils.generateName(i), args[i]);
            }

        }
    }

二、Route初始化加载

2.1、GatewayAutoConfiguration加载RouteLocator

  Spring-Cloud-Gateway路由信息是通过路由定位器RouteLocator加载以及初始化。

  在Spring-Cloud-Gateway初始化时,同时GatewayAutoConfiguration核心配置类会被初始化加载如下 :

    /**
     * 创建一个根据RouteDefinition转换的路由定位器
     */
    @Bean
    public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
                                                   List<GatewayFilterFactory> GatewayFilters,
                                                   List<RoutePredicateFactory> predicates,
                                                   RouteDefinitionLocator routeDefinitionLocator) {
        return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates, GatewayFilters, properties);
    }

    /**
     * 创建一个缓存路由的路由定位器
     * @param routeLocators
     * @return
     */
    @Bean
    @Primary//在相同的bean中,优先使用用@Primary注解的bean.
    public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {

        //1.创建组合路由定位器,根据(容器)已有的路由定位器集合
        //2.创建缓存功能的路由定位器
        return new CachingRouteLocator(new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
    }

路由定位器的创建流程:

1、RouteDefinitionRouteLocator
2、CompositeRouteLocator
3、CachingRouteLocator
其中 RouteDefinitionRouteLocator 是获取路由的主要地方,CompositeRouteLocator,CachingRouteLocator对路由定位器做了附加功能的包装,最终使用的是CachingRouteLocator对外提供服务

2.2、查看RouteLocator源码:

/**
 * 路由定位器,服务获取路由信息
 * 可以通过 RouteDefinitionRouteLocator 获取 RouteDefinition ,并转换成 Route
 */
public interface RouteLocator {

    /**
     * 获取路由
     */
    Flux<Route> getRoutes();
}

查看RouteLocator实现类

缓存功能实现→CachingRouteLocator

组合功能实现→CompositeRouteLocator

通过路由定义转换路由实现→RouteDefinitionRouteLocator

2.3、缓存功能实现→CachingRouteLocator

// 路由定位器的包装类,实现了路由的本地缓存功能
public class CachingRouteLocator implements RouteLocator {
    //目标路由定位器
    private final RouteLocator delegate;

    /**
     * 路由信息
     * Flux 相当于一个 RxJava Observable,
     * 能够发出 0~N 个数据项,然后(可选地)completing 或 erroring。处理多个数据项作为stream
     */
    private final Flux<Route> routes;

    // 本地缓存,用于缓存路由定位器获取的路由集合
    private final Map<String, List> cache = new HashMap<>();
    public CachingRouteLocator(RouteLocator delegate) {
        this.delegate = delegate;
        routes = CacheFlux.lookup(cache, "routes", Route.class)
                .onCacheMissResume(() -> this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE));
    }
    @Override
    public Flux<Route> getRoutes() {
        return this.routes;
    }

    // 刷新缓存
    public Flux<Route> refresh() {
        this.cache.clear();
        return this.routes;
    }

    @EventListener(RefreshRoutesEvent.class)
    void handleRefresh() {
        refresh();
    }
}

1、路由信息的本地缓存,通过Map<String, List> cache 缓存路由到内存中;
2、此类通过@EventListener(RefreshRoutesEvent.class)监听RefreshRoutesEvent事件实现了对缓存的动态刷新;

注:路由动态刷新,使用GatewayControllerEndpoint发布刷新事件

@RestControllerEndpoint(id = "gateway")
public class GatewayControllerEndpoint implements ApplicationEventPublisherAware{
    // 调用url= /gateway/refresh 刷新缓存中的路由信息
        @PostMapping("/refresh")
    public Mono<Void> refresh() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return Mono.empty();
    }
}

2.4、组合功能实现→CompositeRouteLocator

//组合多个 RRouteLocator 的实现,为Route提供统一获取入口
public class CompositeRouteLocator implements RouteLocator {

    /**
     * 能够发出 0~N 个数据项(RouteLocator),然后(可选地)completing 或 erroring。处理多个数据项作为stream
     */
    private final Flux<RouteLocator> delegates;

    public CompositeRouteLocator(Flux<RouteLocator> delegates) {
        this.delegates = delegates;
    }

    @Override
    public Flux<Route> getRoutes() {
        //this.delegates.flatMap((routeLocator)-> routeLocator.getRoutes());
        return this.delegates.flatMap(RouteLocator::getRoutes);
    }
}

此类将遍历传入的目录路由定位器集合,组合每个路由定位器获取到的路由信息

2.5、通过路由定义转换路由实现→RouteDefinitionRouteLocator

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.gateway.route;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.config.GatewayProperties;
import org.springframework.cloud.gateway.event.FilterArgsEvent;
import org.springframework.cloud.gateway.event.PredicateArgsEvent;
import org.springframework.cloud.gateway.filter.FilterDefinition;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.OrderedGatewayFilter;
import org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
import org.springframework.cloud.gateway.handler.predicate.RoutePredicateFactory;
import org.springframework.cloud.gateway.route.Route.AsyncBuilder;
import org.springframework.cloud.gateway.support.ConfigurationUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.Validator;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;

public class RouteDefinitionRouteLocator implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
    protected final Log logger = LogFactory.getLog(this.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;
    @Autowired
    private Validator validator;

    public RouteDefinitionRouteLocator(RouteDefinitionLocator routeDefinitionLocator, List<RoutePredicateFactory> predicates, List<GatewayFilterFactory> gatewayFilterFactories, GatewayProperties gatewayProperties) {
        this.routeDefinitionLocator = routeDefinitionLocator;
        this.initFactories(predicates);
        gatewayFilterFactories.forEach((factory) -> {
            GatewayFilterFactory var10000 = (GatewayFilterFactory)this.gatewayFilterFactories.put(factory.name(), factory);
        });
        this.gatewayProperties = gatewayProperties;
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    private void initFactories(List<RoutePredicateFactory> predicates) {
        predicates.forEach((factory) -> {
            String key = factory.name();
            if (this.predicates.containsKey(key)) {
                this.logger.warn("A RoutePredicateFactory named " + key + " already exists, class: " + this.predicates.get(key) + ". It will be overwritten.");
            }

            this.predicates.put(key, factory);
            if (this.logger.isInfoEnabled()) {
                this.logger.info("Loaded RoutePredicateFactory [" + key + "]");
            }

        });
    }

    public Flux<Route> getRoutes() {
        return this.routeDefinitionLocator.getRouteDefinitions().map(this::convertToRoute).map((route) -> {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("RouteDefinition matched: " + route.getId());
            }

            return route;
        });
    }

    private Route convertToRoute(RouteDefinition routeDefinition) {
        AsyncPredicate<ServerWebExchange> predicate = this.combinePredicates(routeDefinition);
        List<GatewayFilter> gatewayFilters = this.getFilters(routeDefinition);
        return ((AsyncBuilder)Route.async(routeDefinition).asyncPredicate(predicate).replaceFilters(gatewayFilters)).build();
    }

    private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
        List<GatewayFilter> filters = (List)filterDefinitions.stream().map((definition) -> {
            GatewayFilterFactory factory = (GatewayFilterFactory)this.gatewayFilterFactories.get(definition.getName());
            if (factory == null) {
                throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
            } else {
                Map<String, String> args = definition.getArgs();
                if (this.logger.isDebugEnabled()) {
                    this.logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
                }

                Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
                Object configuration = factory.newConfig();
                ConfigurationUtils.bind(configuration, properties, factory.shortcutFieldPrefix(), definition.getName(), this.validator);
                GatewayFilter gatewayFilter = factory.apply(configuration);
                if (this.publisher != null) {
                    this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
                }

                return gatewayFilter;
            }
        }).collect(Collectors.toList());
        ArrayList<GatewayFilter> ordered = new ArrayList(filters.size());

        for(int i = 0; i < filters.size(); ++i) {
            GatewayFilter gatewayFilter = (GatewayFilter)filters.get(i);
            if (gatewayFilter instanceof Ordered) {
                ordered.add(gatewayFilter);
            } else {
                ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
            }
        }

        return ordered;
    }

    private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
        List<GatewayFilter> filters = new ArrayList();
        if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
            filters.addAll(this.loadGatewayFilters("defaultFilters", this.gatewayProperties.getDefaultFilters()));
        }

        if (!routeDefinition.getFilters().isEmpty()) {
            filters.addAll(this.loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters()));
        }

        AnnotationAwareOrderComparator.sort(filters);
        return filters;
    }

    private AsyncPredicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
        List<PredicateDefinition> predicates = routeDefinition.getPredicates();
        AsyncPredicate<ServerWebExchange> predicate = this.lookup(routeDefinition, (PredicateDefinition)predicates.get(0));

        AsyncPredicate found;
        for(Iterator var4 = predicates.subList(1, predicates.size()).iterator(); var4.hasNext(); predicate = predicate.and(found)) {
            PredicateDefinition andPredicate = (PredicateDefinition)var4.next();
            found = this.lookup(routeDefinition, andPredicate);
        }

        return predicate;
    }

    private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {
        RoutePredicateFactory<Object> factory = (RoutePredicateFactory)this.predicates.get(predicate.getName());
        if (factory == null) {
            throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());
        } else {
            Map<String, String> args = predicate.getArgs();
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("RouteDefinition " + route.getId() + " applying " + args + " to " + predicate.getName());
            }

            Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
            Object config = factory.newConfig();
            ConfigurationUtils.bind(config, properties, factory.shortcutFieldPrefix(), predicate.getName(), this.validator);
            if (this.publisher != null) {
                this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties));
            }

            return factory.applyAsync(config);
        }
    }
}

此类的核心方法getRoutes通过传入的routeDefinitionLocator获取路由定位,并循环遍历路由定位依次转换成路由返回,
代码中可以看到getRoutes通过convertToRoute方法将路由定位转换成路由的

2.5.1、RouteDefinition转换:convertToRoute

    // RouteDefinition 转换为对应的Route
    private Route convertToRoute(RouteDefinition routeDefinition) {
        //获取routeDefinition中的Predicate信息
        Predicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
        //获取routeDefinition中的GatewayFilter信息
        List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
        //构建路由信息
        return Route.builder(routeDefinition)
                .predicate(predicate)
                .replaceFilters(gatewayFilters)
                .build();
    }

convertToRoute方法功能作用
  获取routeDefinition中的Predicate信息 (通过combinePredicates方法)
  获取routeDefinition中的GatewayFilter信息(通过gatewayFilters方法)
  构建路由信息

1、convertToRoute中combinePredicates获取routeDefinition中的Predicate信息如下:

    // 返回组合的谓词
    private Predicate<ServerWebExchange> combinePredicates(RouteDefinition routeDefinition) {
        //获取RouteDefinition中的PredicateDefinition集合
        List<PredicateDefinition> predicates = routeDefinition.getPredicates();

        Predicate<ServerWebExchange> predicate = lookup(routeDefinition, predicates.get(0));

        for (PredicateDefinition andPredicate : predicates.subList(1, predicates.size())) {
            Predicate<ServerWebExchange> found = lookup(routeDefinition, andPredicate);
             //流程4
            //返回一个组合的谓词,表示该谓词与另一个谓词的短路逻辑AND
            predicate = predicate.and(found);
        }

        return predicate;
    }

    /**
     * 获取一个谓语定义(PredicateDefinition)转换的谓语
     * @param route
     * @param predicate
     * @return
     */
    @SuppressWarnings("unchecked")
    private Predicate<ServerWebExchange> lookup(RouteDefinition route, PredicateDefinition predicate) {
        //流程1
        //流程1==获取谓语创建工厂
        RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
        if (factory == null) {
            throw new IllegalArgumentException("Unable to find RoutePredicateFactory with name " + predicate.getName());
        }
        //流程2
        //获取参数
        Map<String, String> args = predicate.getArgs();
        if (logger.isDebugEnabled()) {
            logger.debug("RouteDefinition " + route.getId() + " applying "
                    + args + " to " + predicate.getName());
        }

        //组装参数
        Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
        //构建创建谓语的配置信息
        Object config = factory.newConfig();
        ConfigurationUtils.bind(config, properties,
                factory.shortcutFieldPrefix(), predicate.getName(), validator);
        if (this.publisher != null) {
            this.publisher.publishEvent(new PredicateArgsEvent(this, route.getId(), properties));
        }
        //流程3
        //通过谓语工厂构建谓语
        return factory.apply(config);
    }

获取Predicate流程:

  • 根据PredicateDefinition name 获取 RoutePredicateFactory
  • 根据PredicateDefinition args 组装 config信息
  • 通过RoutePredicateFactory 根据config信息创建Predicate信息
  • 多个Predicate 以短路逻辑AND组合

2、convertToRoute中 getFilters获取routeDefinition中的GatewayFilter信息

private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
        List<GatewayFilter> filters = new ArrayList<>();

        //校验gatewayProperties是否含义默认的过滤器集合
        if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
            //加载全局配置的默认过滤器集合
            filters.addAll(loadGatewayFilters("defaultFilters",
                    this.gatewayProperties.getDefaultFilters()));
        }

        if (!routeDefinition.getFilters().isEmpty()) {
            //加载路由定义中的过滤器集合
            filters.addAll(loadGatewayFilters(routeDefinition.getId(), routeDefinition.getFilters()));
        }

        //排序
        AnnotationAwareOrderComparator.sort(filters);
        return filters;
    }
     /**
     * 加载过滤器,根据过滤器的定义加载
     * @param id
     * @param filterDefinitions
     * @return
     */
    @SuppressWarnings("unchecked")
    private List<GatewayFilter> loadGatewayFilters(String id, List<FilterDefinition> filterDefinitions) {
        //遍历过滤器定义,将过滤器定义转换成对应的过滤器
        List<GatewayFilter> filters = filterDefinitions.stream()
                .map(definition -> {

                   //流程1    //通过过滤器定义名称获取过滤器创建工厂
                    GatewayFilterFactory factory = this.gatewayFilterFactories.get(definition.getName());
                    if (factory == null) {
                        throw new IllegalArgumentException("Unable to find GatewayFilterFactory with name " + definition.getName());
                    }
                    //流程2
                    //获取参数
                    Map<String, String> args = definition.getArgs();
                    if (logger.isDebugEnabled()) {
                        logger.debug("RouteDefinition " + id + " applying filter " + args + " to " + definition.getName());
                    }

                    //根据args组装配置信息
                    Map<String, Object> properties = factory.shortcutType().normalize(args, factory, this.parser, this.beanFactory);
                    //构建过滤器创建配置信息
                    Object configuration = factory.newConfig();
                    ConfigurationUtils.bind(configuration, properties,
                            factory.shortcutFieldPrefix(), definition.getName(), validator);

//流程3
                    //通过过滤器工厂创建GatewayFilter
                    GatewayFilter gatewayFilter = factory.apply(configuration);
                    if (this.publisher != null) {
                        //发布事件
                        this.publisher.publishEvent(new FilterArgsEvent(this, id, properties));
                    }
                    return gatewayFilter;
                })
                .collect(Collectors.toList());

        ArrayList<GatewayFilter> ordered = new ArrayList<>(filters.size());
        //包装过滤器使其所有过滤器继承Ordered属性,可进行排序
        for (int i = 0; i < filters.size(); i++) {
            GatewayFilter gatewayFilter = filters.get(i);
            if (gatewayFilter instanceof Ordered) {
                ordered.add(gatewayFilter);
            }
            else {
                ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
            }
        }

        return ordered;
    }
  • getFilters 方法 同时加载 全局配置 gatewayProperties与routeDefinition配置下的所有过滤器定义filterDefinitions
  • loadGatewayFilters 负责将filterDefinition转化成对应的GatewayFilter
    转化流程如下
  1. 根据filterDefinition name 获取 GatewayFilterFactory
  2. 根据filterDefinition args 组装 config信息
  3. 通过GatewayFilterFactory 根据config信息创建PGatewayFilter信息

原文地址:https://www.cnblogs.com/bjlhx/p/9785528.html

时间: 2024-12-21 13:55:42

006-spring cloud gateway-GatewayAutoConfiguration核心配置-GatewayProperties初始化加载、Route初始化加载的相关文章

Spring Cloud Gateway的动态路由实现

1.前言 网关中有两个重要的概念,那就是路由配置和路由规则,路由配置是指配置某请求路径路由到指定的目的地址.而路由规则是指匹配到路由配置之后,再根据路由规则进行转发处理.Spring Cloud Gateway作为所有请求流量的入口,在实际生产环境中为了保证高可靠和高可用,尽量避免重启,需要实现Spring Cloud Gateway动态路由配置.前面章节介绍了Spring Cloud Gateway提供的两种方法去配置路由规则,但都是在Spring Cloud Gateway启动时候,就将路由

第二代微服务网关组件 - Spring Cloud Gateway

[TOC] 初识Spring Cloud Gateway 简介: Spring Cloud Gateway是Spring Cloud体系的第二代网关组件,基于Spring 5.0的新特性WebFlux进行开发,底层网络通信框架使用的是Netty,所以其吞吐量高.性能强劲,未来将会取代第一代的网关组件Zuul.Spring Cloud Gateway可以通过服务发现组件自动转发请求,默认集成了Ribbon做负载均衡,以及默认使用Hystrix对网关进行保护,当然也可以选择其他的容错组件,例如Sen

Spring Cloud Gateway - 扩展

[TOC] Spring Cloud Gateway的监控端点 说到监控,就应该能想到Spring Boot Actuator.而Spring Cloud Gateway基于Actuator提供了许多的监控端点.只需要在项目中添加spring-boot-starter-actuator依赖,并将 gateway 端点暴露,即可获得若干监控端点.配置示例: management: endpoints: web: exposure: include: gateway # 或者配置"*"暴露

API网关spring cloud gateway和负载均衡框架ribbon实战

通常我们如果有一个服务,会部署到多台服务器上,这些微服务如果都暴露给客户,是非常难以管理的,我们系统需要有一个唯一的出口,API网关是一个服务,是系统的唯一出口.API网关封装了系统内部的微服务,为客户端提供一个定制的API.客户端只需要调用网关接口,就可以调用到实际的微服务,实际的服务对客户不可见,并且容易扩展服务. API网关可以结合ribbon完成负载均衡的功能,可以自动检查微服务的状况,及时剔除或者加入某个微服务到可用服务列表.此外网关可以完成权限检查.限流.统计等功能.下面我们将一一完

Spring Cloud Gateway 结合配置中心限流

前言 假设你领导给你安排了一个任务,具体需求如下: 针对具体的接口做限流 不同接口限流的力度可以不同 可以动态调整限流配置,实时生效 如果你接到上面的任务,你会怎么去设计+实现呢? 每个人看待问题的角度不同,自然思考出来的方案也不同,正所谓条条大路通罗马,能到达目的地的路那就是一条好路. 如何分析需求 下面我给出我的实现方式,仅供各位参考,大牛请忽略. 具体问题具体分析,针对需求点,分别去做分析. 需求一 "如何针对具体的接口做限流" 这个在上篇文章中也有讲过,只需要让KeyResol

最全面的改造Zuul网关为Spring Cloud Gateway(包含Zuul核心实现和Spring Cloud Gateway核心实现)

前言: 最近开发了Zuul网关的实现和Spring Cloud Gateway实现,对比Spring Cloud Gateway发现后者性能好支持场景也丰富.在高并发或者复杂的分布式下,后者限流和自定义拦截也很棒. 提示: 本文主要列出本人开发的Zuul网关核心代码以及Spring Cloud Gateway核心代码实现.因为本人技术有限,主要是参照了 Spring Cloud Gateway 如有不足之处还请见谅并留言指出. 1:为什么要做网关 (1)网关层对外部和内部进行了隔离,保障了后台服

Spring Cloud Gateway入坑记

Spring Cloud Gateway入坑记 前提 最近在做老系统的重构,重构完成后新系统中需要引入一个网关服务,作为新系统和老系统接口的适配和代理.之前,很多网关应用使用的是Spring-Cloud-Netfilx基于Zuul1.x版本实现的那套方案,但是鉴于Zuul1.x已经停止迭代,它使用的是比较传统的阻塞(B)IO + 多线程的实现方案,其实性能不太好.后来Spring团队干脆自己重新研发了一套网关组件,这个就是本次要调研的Spring-Cloud-Gateway. 简介 Spring

spring cloud gateway网关启动报错:No qualifying bean of type &#39;org.springframework.web.reactive.DispatcherHandler&#39;

网关配置好后启动报错如下: org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is java.lang.RuntimeException: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'servletEndpoint

那些年我们一起踩过的Spring Cloud Gateway获取body的那些坑

Spring Cloud Gateway-获取body踩坑实践 问题1:无法获取body内容 问题原因分析 在使用过程中碰到过滤器中获取的内容一直都是空的,尝试了网上的各种解析body内容的方法,但是得到结果都是一样,死活获取不到body数据,一度很崩溃.后来进行了各种尝试,最终发现使用不同的spring boot版本和spring cloud版本,对结果影响很大. 最佳实践 方案1:降低版本 springboot版本:2.0.5-RELEASE springcloud版本:Finchley.R