SpringCloudGateway源码阅读(一)核心概念及路由加载

「微服务网关实战五」做网关系统, 99% 会被问到这个功能 好了,今天的文章就是以上这些内容了,相关源代码在这里,本篇主要的重点是路由动态刷新的讲解,干货满满,相信大家不会失望。其实通过 Nacos 配置路由还有一点点不够好的地方,就是如果你的路由有几十个甚至上百个的话,在 Nacos 控制台操作起来非常不易,因为文件行数太长了,这个时候如果能通过前端做一个控制台,直接通过可视化页面进行各种交互就更好了,这个功能正好我还真做了,在后面的文章中将于大家分享。作者:和耳朵。 阅读详情

一、核心概念

路由Route

路由是网关的核心抽象。

public class Route implements Ordered {
    // 唯一id
    private final String id;
    // 跳转uri
    private final URI uri;
    // SpringBean优先级
    private final int order;
    // 断言
    private final AsyncPredicate<ServerWebExchange> predicate;
    // 当前路由特有的过滤器
    private final List<GatewayFilter> gatewayFilters;
    // 元数据
    private final Map<String, Object> metadata;
}
复制代码

ServerWebExchange

ServerWebExchange是spring-web的一个接口,提供ServerHttpRequest、ServerHttpResponse,ApplicationContext等实例的get方法。

断言AsyncPredicate

断言用于判断路由是否匹配某个ServerWebExchange。

public interface AsyncPredicate<T> extends Function<T, Publisher<Boolean>> {
    // 构造与AsyncPredicate
    default AsyncPredicate<T> and(AsyncPredicate<? super T> other) {
        return new AndAsyncPredicate<>(this, other);
    }
    // 构造非AsyncPredicate
    default AsyncPredicate<T> negate() {
        return new NegateAsyncPredicate<>(this);
    }
    // 构造或AsyncPredicate
    default AsyncPredicate<T> or(AsyncPredicate<? super T> other) {
        return new OrAsyncPredicate<>(this, other);
    }
    // 构造默认AsyncPredicate
    static AsyncPredicate<ServerWebExchange> from(
            Predicate<? super ServerWebExchange> predicate) {
        return new DefaultAsyncPredicate<>(GatewayPredicate.wrapIfNeeded(predicate));
    }
    // 默认AsyncPredicate
    class DefaultAsyncPredicate<T> implements AsyncPredicate<T> {

        private final Predicate<T> delegate;

        public DefaultAsyncPredicate(Predicate<T> delegate) {
            this.delegate = delegate;
        }

        @Override
        public Publisher<Boolean> apply(T t) {
            return Mono.just(delegate.test(t));
        }

    }
    // 非AsyncPredicate
    class NegateAsyncPredicate<T> implements AsyncPredicate<T> {

        private final AsyncPredicate<? super T> predicate;

        public NegateAsyncPredicate(AsyncPredicate<? super T> predicate) {
            this.predicate = predicate;
        }

        @Override
        public Publisher<Boolean> apply(T t) {
            return Mono.from(predicate.apply(t)).map(b -> !b);
        }

    }
    // 与AsyncPredicate
    class AndAsyncPredicate<T> implements AsyncPredicate<T> {

        private final AsyncPredicate<? super T> left;

        private final AsyncPredicate<? super T> right;

        public AndAsyncPredicate(AsyncPredicate<? super T> left,
                AsyncPredicate<? super T> right) {
            this.left = left;
            this.right = right;
        }

        @Override
        public Publisher<Boolean> apply(T t) {
            return Mono.from(left.apply(t)).flatMap(
                    result -> !result ? Mono.just(false) : Mono.from(right.apply(t)));
        }
    }
    // 或AsyncPredicate
    class OrAsyncPredicate<T> implements AsyncPredicate<T> {

        private final AsyncPredicate<? super T> left;

        private final AsyncPredicate<? super T> right;

        public OrAsyncPredicate(AsyncPredicate<? super T> left,
                AsyncPredicate<? super T> right) {
            this.left = left;
            this.right = right;
        }

        @Override
        public Publisher<Boolean> apply(T t) {
            return Mono.from(left.apply(t)).flatMap(
                    result -> result ? Mono.just(true) : Mono.from(right.apply(t)));
        }

    }

}
复制代码

路由过滤器GatewayFilter

针对于路由的过滤器,无法离开Route而存在。

public interface GatewayFilter extends ShortcutConfigurable {
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
复制代码

全局过滤器GlobalFilter

全局的过滤器,所有路由都必须执行的过滤器。后续Bean实例化的时候,会适配成GatewayFilter被使用。

public interface GlobalFilter {
    Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
复制代码

过滤器链GatewayFilterChain

GatewayFilterChain过滤器链允许GatewayFilter过滤器按顺序,挨个执行。

public interface GatewayFilterChain {
    Mono<Void> filter(ServerWebExchange exchange);
}
复制代码

路由定义RouteDefinition

类似于Spring的BeanDefinition,Route的一种构建方式就是通过RouteDefinition,比如从properties文件中解析得到的路由规则定义。

public class RouteDefinition {
    // 唯一id
    private String id;
        // 断言定义
    private List<PredicateDefinition> predicates = new ArrayList<>();
    // 过滤器定义
    private List<FilterDefinition> filters = new ArrayList<>();
    // 跳转uri
    private URI uri;
    // 元数据
    private Map<String, Object> metadata = new HashMap<>();
    // Spring优先级
    private int order = 0;
}
复制代码

断言定义PredicateDefinition

从配置文件加载的断言定义,构造Route时,会用RoutePredicateFactory#applyAsync转换成AsyncPredicate。

public class PredicateDefinition {
    private String name;
    private Map<String, String> args = new LinkedHashMap<>();
    public PredicateDefinition() {
    }
    // predicates:
    //     - Path=/echo // 解析'Path=/echo'放入args
    public PredicateDefinition(String text) {
        int eqIdx = text.indexOf('=');
        // 设置name
        setName(text.substring(0, eqIdx));
    
        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");
        // 设置args
        for (int i = 0; i < args.length; i++) {
            this.args.put(NameUtils.generateName(i), args[i]);
        }
    }
}
复制代码

路由过滤器定义FilterDefinition

从配置文件加载的路由过滤器定义,构造Route时,会用GatewayFilterFactory#apply转换为GatewayFilter。

public class FilterDefinition {
    private String name;
    private Map<String, String> args = new LinkedHashMap<>();
    public FilterDefinition() {
    }
    // 解析配置文件 PrefixPath=/httpbin
    public FilterDefinition(String text) {
        int eqIdx = text.indexOf('=');
        if (eqIdx <= 0) {
            setName(text);
            return;
        }
        setName(text.substring(0, eqIdx));

        String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ",");

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

获取路由定义RouteDefinitionLocator

RouteDefinitionLocator具有获取路由定义的能力。

public interface RouteDefinitionLocator {
    Flux<RouteDefinition> getRouteDefinitions();
}
复制代码

最后对外暴露的实际是CompositeRouteDefinitionLocator,他组合了所有RouteDefinitionLocator。

获取路由RouteLocator

RouteLocator具有获取路由Route的能力。网关处理请求时只会调用RouteLocator获取Route,通过Route的断言和过滤处理请求。

public interface RouteLocator {
    Flux<Route> getRoutes();
}
复制代码

Spring容器加载的时候,会把路由都放到CachingRouteLocator里,后续运行时只会和CachingRouteLocator打交道。

 

二、加载路由

讲解从Gateway的Bean装配,到加载Route到CachingRouteLocator。

自动配置

Spring-Cloud-Gateway的自动配置类是org.springframework.cloud.gateway.config.GatewayAutoConfiguration。重点看一些重要的Bean装配,全局Filter等下一章节讲请求流程的时候再分析。

Gateway配置文件

@Bean
public GatewayProperties gatewayProperties() {
    return new GatewayProperties();
}
@ConfigurationProperties("spring.cloud.gateway")
@Validated
public class GatewayProperties {
    // 路由
    private List<RouteDefinition> routes = new ArrayList<>();
    // 默认过滤器
    private List<FilterDefinition> defaultFilters = new ArrayList<>();
}
复制代码

RouteDefinitionLocator相关

  • PropertiesRouteDefinitionLocator:配置文件创建RouteDefinitionLocator
@Bean
@ConditionalOnMissingBean
public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(
        GatewayProperties properties) {
    return new PropertiesRouteDefinitionLocator(properties);
}
复制代码
  • InMemoryRouteDefinitionRepository:内存级别路由定义,无法持久化,支持动态新增和删除路由定义
@Bean
@ConditionalOnMissingBean(RouteDefinitionRepository.class)
public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
    return new InMemoryRouteDefinitionRepository();
}
复制代码
  • CompositeRouteDefinitionLocator:组合其他所有的RouteDefinitionLocator,并且是Primary的
@Bean
@Primary
public RouteDefinitionLocator routeDefinitionLocator(
        List<RouteDefinitionLocator> routeDefinitionLocators) {
    return new CompositeRouteDefinitionLocator(
            Flux.fromIterable(routeDefinitionLocators));
}
复制代码

RouteLocator相关

  • RouteLocatorBuilder:辅助用编码方式注入自定义的RouteLocator。
@Bean
public RouteLocatorBuilder routeLocatorBuilder(
        ConfigurableApplicationContext context) {
    return new RouteLocatorBuilder(context);
}
复制代码
  • RouteDefinitionRouteLocator:用RouteDefinitionLocator和GatewayFilterFactory和RoutePredicateFactory构造Route,创建RouteLocator。
@Bean
public RouteLocator routeDefinitionRouteLocator(GatewayProperties properties,
        List<GatewayFilterFactory> gatewayFilters,
        List<RoutePredicateFactory> predicates,
        RouteDefinitionLocator routeDefinitionLocator,
        ConfigurationService configurationService) {
    return new RouteDefinitionRouteLocator(routeDefinitionLocator, predicates,
            gatewayFilters, properties, configurationService);
}
复制代码
  • CachingRouteLocator:委托CompositeRouteLocator聚合其他所有RouteLocator,实现RouteLocator。
@Bean
@Primary
@ConditionalOnMissingBean(name = "cachedCompositeRouteLocator")
public RouteLocator cachedCompositeRouteLocator(List<RouteLocator> routeLocators) {
    return new CachingRouteLocator(
            new CompositeRouteLocator(Flux.fromIterable(routeLocators)));
}
复制代码

加载路由入口类RouteRefreshListener

@Bean
public RouteRefreshListener routeRefreshListener(ApplicationEventPublisher publisher) {
    return new RouteRefreshListener(publisher);
}
复制代码

加载路由到CachingRouteLocator

 

RouteRefreshListener

加载路由到RouteLocator的入口,通过Spring事件触发。

public class RouteRefreshListener implements ApplicationListener<ApplicationEvent> {

    private final ApplicationEventPublisher publisher;

    public RouteRefreshListener(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ContextRefreshedEvent
                || event instanceof RefreshScopeRefreshedEvent
                || event instanceof InstanceRegisteredEvent) {
            reset();
        }
        // ... 省略其他事件判断,也可能触发reset
    }
    
    // 发布RefreshRoutesEvent事件
    private void reset() {
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
    }

}
复制代码

CachingRouteLocator

CachingRouteLocator收到RefreshRoutesEvent,委托CompositeRouteLocator获取Flux<Route>放入自己的缓存cache中。

public class CachingRouteLocator implements Ordered, RouteLocator,
        ApplicationListener<RefreshRoutesEvent>, ApplicationEventPublisherAware {
    // 写死的缓存cache的key
    private static final String CACHE_KEY = "routes";
    // CompositeRouteLocator
    private final RouteLocator delegate;
    // Route列表
    private final Flux<Route> routes;
    // 缓存
    private final Map<String, List> cache = new ConcurrentHashMap<>();
    // 事件发布者
    private ApplicationEventPublisher applicationEventPublisher;

    public CachingRouteLocator(RouteLocator delegate) {
        this.delegate = delegate;
        // 这里并不会触发fetch,只有当需要routes的时候才会触发fetch,比如getRoutes()
        routes = CacheFlux.lookup(cache, CACHE_KEY, Route.class)
                .onCacheMissResume(this::fetch);
    }
    // 委托CompositeRouteLocator获取Route并排序
    private Flux<Route> fetch() {
        return this.delegate.getRoutes().sort(AnnotationAwareOrderComparator.INSTANCE);
    }
    // 获取Route,如果routes为空,会触发fetch
    @Override
    public Flux<Route> getRoutes() {
        return this.routes;
    }
    // 清空缓存
    public Flux<Route> refresh() {
        this.cache.clear();
        return this.routes;
    }
    // 接收RefreshRoutesEvent
    @Override
    public void onApplicationEvent(RefreshRoutesEvent event) {
        try {
            // 委托CompositeRouteLocator获取Route并排序
            fetch()
            .collect(Collectors.toList())
            .subscribe(list -> Flux.fromIterable(list)
                  .materialize().collect(Collectors.toList()).subscribe(signals -> {
                      applicationEventPublisher.publishEvent(new RefreshRoutesResultEvent(this));
                      // 放入缓存
                      cache.put(CACHE_KEY, signals);
                  }, throwable -> handleRefreshError(throwable)));
        }
        catch (Throwable e) {
            handleRefreshError(e);
        }
    }
    // 发生异常发布RefreshRoutesResultEvent事件
    private void handleRefreshError(Throwable throwable) {
        applicationEventPublisher
                .publishEvent(new RefreshRoutesResultEvent(this, throwable));
    }
    void handleRefresh() {
        refresh();
    }
    @Override
    public int getOrder() {
        return 0;
    }
    @Override
    public void setApplicationEventPublisher(
            ApplicationEventPublisher applicationEventPublisher) {
        this.applicationEventPublisher = applicationEventPublisher;
    }
}
复制代码

CompositeRouteLocator

通过其他RouteLocator获取所有Route。

public class CompositeRouteLocator implements RouteLocator {
    // 其他所有RouteLocator,除了CachingRouteLocator
    private final Flux<RouteLocator> delegates;
    public CompositeRouteLocator(Flux<RouteLocator> delegates) {
        this.delegates = delegates;
    }
    @Override
    public Flux<Route> getRoutes() {
        return this.delegates.flatMapSequential(RouteLocator::getRoutes);
    }
}
复制代码

1 编码方式获取Route

@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
    return builder.routes()
            .route(r -> r.host("**.abc.org").and().path("/anything/png")
                .filters(f ->
                        f.prefixPath("/httpbin")
                                .addResponseHeader("X-TestHeader", "foobar"))
                .uri(uri)
            )
            .build();
}
复制代码

RouteLocatorBuilder.Builder构造的RouteLocator,Bean注入的时候直接构造完成了。具体构造过程不细看了,也是利用了RoutePredicateFactory和GatewayFilterFactory。

public static class Builder {
    private List<Route.AsyncBuilder> routes = new ArrayList<>();
    public RouteLocator build() {
        return () -> Flux.fromIterable(this.routes)
                .map(routeBuilder -> routeBuilder.build());
    }
复制代码

2 RouteDefinitionRouteLocator

RouteDefinitionRouteLocator只负责通过RouteDefinition创建Route,委托CompositeRouteDefinitionLocator获取RouteDefinition,并通过ConfigurationService、RoutePredicateFactory、GatewayFilterFactory将RouteDefinition转换为Route返回。

public class RouteDefinitionRouteLocator
        implements RouteLocator, BeanFactoryAware, ApplicationEventPublisherAware {
    // 默认过滤器名字
    public static final String DEFAULT_FILTERS = "defaultFilters";
    // 委托CompositeRouteDefinitionLocator
    private final RouteDefinitionLocator routeDefinitionLocator;
    // ConfigurationService操作RoutePredicateFactory和GatewayFilterFactory
    // 转换断言和过滤器
    private final ConfigurationService configurationService;
    // name - RoutePredicateFactory
    private final Map<String, RoutePredicateFactory> predicates = new LinkedHashMap<>();
    // name - GatewayFilterFactory
    private final Map<String, GatewayFilterFactory> gatewayFilterFactories = new HashMap<>();
    // spring.cloud.gateway配置文件
    private final GatewayProperties gatewayProperties;
    
    @Override
    public Flux<Route> getRoutes() {
        Flux<Route> routes = this.routeDefinitionLocator
                // 委托CompositeRouteDefinitionLocator获取RouteDefinition
                .getRouteDefinitions()
                // 转换为Route
                .map(this::convertToRoute);
        // 如果spring.cloud.gateway.failOnRouteDefinitionError=true(默认)
        // 仅仅打印日志
        if (!gatewayProperties.isFailOnRouteDefinitionError()) {
            routes = routes.onErrorContinue((error, obj) -> {
                    logger.warn(...);
            });
        }
        return routes;
    }
}
复制代码
  • CompositeRouteDefinitionLocator

getRouteDefinitions循环所有RouteDefinitionLocator获取所有RouteDefinition。

public class CompositeRouteDefinitionLocator implements RouteDefinitionLocator {
  private final Flux<RouteDefinitionLocator> delegates;
  private final IdGenerator idGenerator;
  public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates) {
      this(delegates, new AlternativeJdkIdGenerator());
  }
  public CompositeRouteDefinitionLocator(Flux<RouteDefinitionLocator> delegates,
          IdGenerator idGenerator) {
      this.delegates = delegates;
      this.idGenerator = idGenerator;
  }

  @Override
  public Flux<RouteDefinition> getRouteDefinitions() {
      return this.delegates
              // 委托所有其他RouteDefinitionLocator获取RouteDefinition
              .flatMapSequential(RouteDefinitionLocator::getRouteDefinitions)
              .flatMap(routeDefinition -> {
                  // 如果RouteDefinition没有设置id,随便给一个
                  if (routeDefinition.getId() == null) {
                      return randomId().map(id -> {
                          routeDefinition.setId(id);
                          return routeDefinition;
                      });
                  }
                  return Mono.just(routeDefinition);
              });
  }
  // 获取随机id
  protected Mono<String> randomId() {
      return Mono.fromSupplier(idGenerator::toString)
              .publishOn(Schedulers.boundedElastic());
  }
}
复制代码

RouteDefinitionLocator有很多种,以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());
  }
}
复制代码
  • RouteDefinitionRouteLocator.convertToRoute

通过ConfigurationService、RoutePredicateFactory、GatewayFilterFactory将RouteDefinition转换为Route。

private Route convertToRoute(RouteDefinition routeDefinition) {
  // 将routeDefinition里的PredicateDefinition
  // 通过RoutePredicateFactory转换为AsyncPredicate
  AsyncPredicate<ServerWebExchange> predicate = combinePredicates(routeDefinition);
  // 将routeDefinition里的FilterDefinition
  // 通过GatewayFilterFactory转换为GatewayFilter
  List<GatewayFilter> gatewayFilters = getFilters(routeDefinition);
  // 组装Route
  return Route.async(routeDefinition).asyncPredicate(predicate)
          .replaceFilters(gatewayFilters).build();
}
复制代码

RouteDefinitionRouteLocator#combinePredicates转换PredicateDefinition为AsyncPredicate。

private AsyncPredicate<ServerWebExchange> combinePredicates(
            RouteDefinition routeDefinition) {
    List<PredicateDefinition> predicates = routeDefinition.getPredicates();
    // 先获取第一个断言定义,转换为AsyncPredicate
    AsyncPredicate<ServerWebExchange> predicate = lookup(routeDefinition,
            predicates.get(0));
    // 后续定义用and连接
    for (PredicateDefinition andPredicate : predicates.subList(1,
            predicates.size())) {
        AsyncPredicate<ServerWebExchange> found = lookup(routeDefinition,
                andPredicate);
        predicate = predicate.and(found);
    }
    return predicate;
}
private AsyncPredicate<ServerWebExchange> lookup(RouteDefinition route,
            PredicateDefinition predicate) {
  // 通过PredicateDefinition的name找到对应的RoutePredicateFactory
  RoutePredicateFactory<Object> factory = this.predicates.get(predicate.getName());
  // ConfigurationService操作RouteDefinition和RoutePredicateFactory
  Object config = this.configurationService.with(factory)
          .name(predicate.getName())
          .properties(predicate.getArgs())
          .eventFunction((bound, properties) -> new PredicateArgsEvent(
                  RouteDefinitionRouteLocator.this, route.getId(), properties))
          .bind();
  return factory.applyAsync(config);
}
复制代码

RouteDefinitionRouteLocator#getFilters将FilterDefinition转换为GatewayFilter。

private List<GatewayFilter> getFilters(RouteDefinition routeDefinition) {
  List<GatewayFilter> filters = new ArrayList<>();
  // 如果默认过滤器不为空,加入默认过滤器
  if (!this.gatewayProperties.getDefaultFilters().isEmpty()) {
      filters.addAll(loadGatewayFilters(DEFAULT_FILTERS,
              new ArrayList<>(this.gatewayProperties.getDefaultFilters())));
  }
  // 如果routeDefinition里的过滤器不为空,加入过滤器
  if (!routeDefinition.getFilters().isEmpty()) {
      filters.addAll(loadGatewayFilters(routeDefinition.getId(),
              new ArrayList<>(routeDefinition.getFilters())));
  }
  // 排序
  AnnotationAwareOrderComparator.sort(filters);
  return filters;
}
List<GatewayFilter> loadGatewayFilters(String id,List<FilterDefinition> filterDefinitions) {
  ArrayList<GatewayFilter> ordered = new ArrayList<>(filterDefinitions.size());
  for (int i = 0; i < filterDefinitions.size(); i++) {
      // Filter定义 
      FilterDefinition definition = filterDefinitions.get(i);
      // 根据Filter定义的name获取GatewayFilterFactory
      GatewayFilterFactory factory = this.gatewayFilterFactories
              .get(definition.getName());
      // 配置
      Object configuration = this.configurationService.with(factory)
              .name(definition.getName())
              .properties(definition.getArgs())
              .eventFunction((bound, properties) -> new FilterArgsEvent(
                      RouteDefinitionRouteLocator.this, id, (Map<String, Object>) properties))
              .bind();
      // 转换为GatewayFilter
      GatewayFilter gatewayFilter = factory.apply(configuration);
      if (gatewayFilter instanceof Ordered) {
          ordered.add(gatewayFilter);
      }
      else {
          ordered.add(new OrderedGatewayFilter(gatewayFilter, i + 1));
      }
  }

  return ordered;
}
复制代码

总结

  • 理清Route、RouteLocator、RouteDefinition、RouteDefinitionLocator的含义。最后对运行时实际暴露的对象只有CachingRouteLocator和Route。
  • RouteRefreshListener接收容器事件,发布RefreshRoutesEvent事件,触发路由加载至CachingRouteLocator。

 

万字长文带你吃透SpringCloudGateway工作原理+动态路由+源码解析 非阻塞,默认使用RxNetty作为响应式Web容器,通过非阻塞方式,利用较少的线程和资源来处理高并发请求,并提升服务资源利用的可伸缩性。函数式编程端点,通过使用Spring WebFlux的函数式编程模式定义路由端点,处理请求。 阅读详情

相关推荐

spring cloud gateway 源码解析

Spring Cloud Gateway 是基于 Spring WebFlux 的响应式网关框架,其核心依赖 starter-gateway 和 starter-webflux。starter-webflux 使用 Reactor Netty 作为嵌入式反应式 HTTP 服务器,负责处理请求。通过分析源码,网关的启动过程涉及 ReactiveWebServerFactoryAutoConfiguration 和 NettyReactiveWebServerFactory,最终在 finishRefresh

renzhe1301的专栏 1144

解决网关不定时出现Refresh routes error !!!

在Nacos 管理端下线服务后,Nacos服务端有定时延迟机制导致不能及时更新状态,导致服务重启后gateway网关依然会把请求分配到已经下线且停机的服务,导致接口提示未找到服务。网关隔一段时间就会报动态刷新路的异常信息,导致线上出现请求网关超时,重启之后网关正常。最近跟踪服务器日志,经常发现如下异常。针对此种情况做出下面解决方案,

vigor(软件开发) 5340

医疗设备安规入门:一张图搞懂BF型设备的MOOP/MOPP绝缘路径(附GB 9706.1附录解析)

本文深入解析了BF型医疗设备的MOOP/MOPP绝缘路径设计,结合GB 9706.1标准附录J的实战应用,帮助工程师快速掌握医疗设备安规要点。通过典型绝缘路径图分析,详细对比了MOOP与MOPP的防护差异,并提供了海拔修正、漏电流测试等关键设计指南,助力医疗设备安全合规。

weixin_30633405的博客 390

Spring Cloud Gateway源码

默认情况下,Spring Cloud Gateway 会根据服务注册中心(例如 Eureka Server)中维护的服务列表,以服务名(spring.application.name)作为路径创建动态路由进行转发,从而实现动态路由功能。使用Spring cloud开发微服务系统,一般采用的架构如下所示,Gateway不仅作为请求转发的入口,还会进行权限验证、监控、缓存、请求路由、流量限制、请求熔断、请求重试等功能。lb:uri 的协议,表示开启 Spring Cloud Gateway 的负载均衡功能。

守正出奇 1684

abb机器人指令手册_ABB机器人配置圆形输送链跟踪

更多内容请点击上方ABB机器人实战技巧关注也可点击公众号下方往期经典浏览更多内容转载请先后台留言,大家一起支持原创,推动机器人使用和发展本公众号对各类ABB机器人应用,仿真,毕业设计提供技术支持,详细后台留言本公众号诚挚希望与各机器人培训机构,机器人使用单元合作,提供技术支持,详细后台留言1. 通常的机器人输送链跟踪,均为直线输送链跟踪,例如下图2. 有些情况,输送链为圆形,例如...

weixin_39849894的博客 2044

深入探索 SEED-VII:情感脑电图研究的新利器

SEED-VII是上海交通大学最新发布的多模态情感脑电图数据集,在传统EEG数据基础上增加了眼动、生理信号等多维信息,支持更精细的情感识别研究。该数据集提供了丰富的情感维度标注(效价和唤醒度),可用于算法基准测试、跨模态情感融合及个性化模型开发等研究场景。在应用层面,SEED-VII可推动人机交互、心理健康监测、教育娱乐等领域的情感计算技术发展。文章还提供了PyTorch加载该数据集的代码示例,为研究者使用该数据集提供了技术参考。

qq_32516809的博客 1747

SpringCloudGateway源码阅读(一)核心概念及路由加载,自定义组件如何注入Spring底层的组件

整理的这些资料希望对Java开发的朋友们有所参考以及少走弯路,本文的重点是你有没有收获与成长,其余的都不重要,希望读者们能谨记这一点。其实面试这一块早在第一个说的25大面试专题就全都有的。以上提及的这些全部的面试+学习的各种笔记资料,我这差不多来回搞了三个多月,收集整理真的很不容易,其中还有很多自己的一些知识总结。正是因为很麻烦,所以对以上这些学习复习资料感兴趣,Factory。小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

qd520_1314的博客 817

别再让CPU干GPU的活了:CST Studio Suite GPU加速深度调优指南(从驱动版本到任务管理器监控)

本文深入探讨了CST Studio Suite的GPU加速深度调优方法,从NVIDIA驱动版本选择到系统级资源管理,再到实时监控与瓶颈诊断技术。通过科学的驱动优化、GPU资源管理策略和高级调优技巧,显著提升仿真效率,特别适合电磁仿真工程师和硬件加速需求的专业用户。

weixin_28740299的博客 166

209 Gateway核心知识

GatewayFilter工厂同Predicate工厂类似,都是在配置文件application.yml中配置,遵循了约定大于配置的思想,只需要在配置文件配置GatewayFilter Factory的名称,而不需要写全部的类名,比如AddRequestHeaderGatewayFilterFactory只需要在配置文件中写AddRequestHeader,而不是全部类名。网关作为流量的,在微服务系统中有着非常作用,网关常见的功能有路由转发、权限校验、限流控制等作用。上,能够满足大多数的需求。

THE ORDER 1507

Cesium 模拟飞机坠毁功能

Cesium 模拟飞机坠毁功能,粒子模拟

QQhelphelp的博客 1068

今日指数项目之实时流数据采集【六】

实时数据采集代码

Maynor的博客 2147

SpringColoud GateWay 核心组件

当监听到路由定义变化事件时,触发路由刷新操作,更新网关的路由规则,重新加载并应用新的路由配置。的值以键值对的方式进行配置,这样在请求过来时会对属性值和正则进行匹配,匹配上才会走路由。都会对当前的客户端请求进行判断,是否满足当前的要求,如果满足则交给当前请求处理。当请求的时间在这个配置的时间之后,请求会被路由到指定的。创建一个全局过滤器类,这也是一个前置过滤器,实现。开头的长度为三位的字符串才会进行匹配和路由。这个配置,遵循契约大于配置的思想,它实际被。,证明路由需要匹配正则表达式才会进行路由。

web13618542420的博客 806

基于TIA博途的一阶滞后滤波+中位值滤波+堆栈平均值滤波算法SCL语言程序(封装FB库)

基于TIA博途的一阶滞后滤波+中位值滤波+堆栈平均值滤波算法SCL语言程序(封装FB库)

Robot_PLC_HMI_Automation 2178

分布式进阶(二一)——分布式框架之可扩展:API网关

本章,我介绍了API网关的作用和动态路由、灰度发布的基本原理。API网关一般是整个分布式系统的门户,所有流量首先需要经过网关处理,所以API网关的性能优化是至关重要的。以笔者曾经做过的一个银行快捷支付系统为例,其架构简化后,主要分为网关模块、联机模块、批量模块,所有支付请求首先要经过F5、Nginx/LVS进行负载均衡,然后到达API网关,由API网关进行服务路由、鉴权、日志记录等处理。所以,生产环境一般都需要根据预判的业务量,提前对整个系统进行压测。

smart_an的专栏 1013

Python爬取小红书种草商品评论数据:从入门到实战全攻略(附反爬+情感分析方案)

Python爬取小红书种草商品评论数据,核心是“抓包找到正确的接口+处理登录验证+合理的反爬策略”。新手不用一开始就追求多笔记批量爬取和情感分析,先把单笔记的评论抓取和存储跑通,再逐步扩展功能。我做的这个系统现在每天帮朋友爬取3-5款美妆产品的评论,自动做情感分析和关键词提取,她再也不用手动翻评论了,效率提升了80%。如果你们在开发中遇到具体问题,比如接口找不到、Cookie过期、IP被封,都可以在评论区留言,我会一一解答。后续也可以出一期小红书笔记种草数据爬取的教程,帮助大家更全面地分析竞品数据。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1350

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Spring Cloud微服务中网关服务是如何实现的?(Zuul篇)

转载自:https://www.javazhiyin.com/34393.html 叙述 Zuul网关服务是如何实现的。 Zuul是Neflix开源的Api Gateway服务器,它本质上是一个Servlet应用,其核心是通过一系列filters的实现来为整个微服务体系提供路由、安全、监控等边界服务。Zuul目前分为两个大版本Zuul1和Zuul2,它们的区别在于Zuul1的IO模型还是B...

lizhengyu891231的博客 269

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

上一篇: 秋招必备!阿里产出的高并发+JVM豪华套餐送给你,绝对硬核干货
下一篇: 吹爆!阿里新产Spring Boot高级笔记,肝完变秃也变强
java架构师小芷
博客等级 码龄6年 216粉丝 519原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值