Spring Cloud GateWay源码解析实战 - RoutePredicateHandlerMapping

简介: Spring Cloud GateWay源码解析实战 - RoutePredicateHandlerMapping
package org.springframework.cloud.gateway.handler;
import java.util.function.Function;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.config.GlobalCorsProperties;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.core.env.Environment;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.reactive.handler.AbstractHandlerMapping;
import org.springframework.web.server.ServerWebExchange;
import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DIFFERENT;
import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.DISABLED;
import static org.springframework.cloud.gateway.handler.RoutePredicateHandlerMapping.ManagementPortType.SAME;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_HANDLER_MAPPER_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR;
/**
 * @author Spencer Gibb
 */
public class RoutePredicateHandlerMapping extends AbstractHandlerMapping {
  private final FilteringWebHandler webHandler;
  private final RouteLocator routeLocator;
  private final Integer managementPort;
  private final ManagementPortType managementPortType;
  public RoutePredicateHandlerMapping(FilteringWebHandler webHandler,
      RouteLocator routeLocator, GlobalCorsProperties globalCorsProperties,
      Environment environment) {
    this.webHandler = webHandler;
    this.routeLocator = routeLocator;
    this.managementPort = getPortProperty(environment, "management.server.");
    this.managementPortType = getManagementPortType(environment);
    setOrder(1);
    setCorsConfigurations(globalCorsProperties.getCorsConfigurations());
  }
  private ManagementPortType getManagementPortType(Environment environment) {
    Integer serverPort = getPortProperty(environment, "server.");
    if (this.managementPort != null && this.managementPort < 0) {
      return DISABLED;
    }
    return ((this.managementPort == null
        || (serverPort == null && this.managementPort.equals(8080))
        || (this.managementPort != 0 && this.managementPort.equals(serverPort)))
            ? SAME : DIFFERENT);
  }
  private static Integer getPortProperty(Environment environment, String prefix) {
    return environment.getProperty(prefix + "port", Integer.class);
  }
  @Override
  protected Mono<?> getHandlerInternal(ServerWebExchange exchange) {
    // don't handle requests on management port if set and different than server port
    if (this.managementPortType == DIFFERENT && this.managementPort != null
        && exchange.getRequest().getURI().getPort() == this.managementPort) {
      return Mono.empty();
    }
    exchange.getAttributes().put(GATEWAY_HANDLER_MAPPER_ATTR, getSimpleName());
    return lookupRoute(exchange)
        // .log("route-predicate-handler-mapping", Level.FINER) //name this
        .flatMap((Function<Route, Mono<?>>) r -> {
          exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
          if (logger.isDebugEnabled()) {
            logger.debug(
                "Mapping [" + getExchangeDesc(exchange) + "] to " + r);
          }
          exchange.getAttributes().put(GATEWAY_ROUTE_ATTR, r);
          return Mono.just(webHandler);
        }).switchIfEmpty(Mono.empty().then(Mono.fromRunnable(() -> {
          exchange.getAttributes().remove(GATEWAY_PREDICATE_ROUTE_ATTR);
          if (logger.isTraceEnabled()) {
            logger.trace("No RouteDefinition found for ["
                + getExchangeDesc(exchange) + "]");
          }
        })));
  }
  @Override
  protected CorsConfiguration getCorsConfiguration(Object handler,
      ServerWebExchange exchange) {
    // TODO: support cors configuration via properties on a route see gh-229
    // see RequestMappingHandlerMapping.initCorsConfiguration()
    // also see
    // https://github.com/spring-projects/spring-framework/blob/master/spring-web/src/test/java/org/springframework/web/cors/reactive/CorsWebFilterTests.java
    return super.getCorsConfiguration(handler, exchange);
  }
  // TODO: get desc from factory?
  private String getExchangeDesc(ServerWebExchange exchange) {
    StringBuilder out = new StringBuilder();
    out.append("Exchange: ");
    out.append(exchange.getRequest().getMethod());
    out.append(" ");
    out.append(exchange.getRequest().getURI());
    return out.toString();
  }
  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);
        })
            // instead of immediately stopping main flux due to error, log and
            // swallow it
            .doOnError(e -> logger.error(
                "Error applying predicate for route: " + route.getId(),
                e))
            .onErrorResume(e -> Mono.empty()))
        // .defaultIfEmpty() put a static Route not found
        // or .switchIfEmpty()
        // .switchIfEmpty(Mono.<Route>empty().log("noroute"))
        .next()
        // TODO: error handling
        .map(route -> {
          if (logger.isDebugEnabled()) {
            logger.debug("Route matched: " + route.getId());
          }
          validateRoute(route, exchange);
          return route;
        });
    /*
     * TODO: trace logging if (logger.isTraceEnabled()) {
     * logger.trace("RouteDefinition did not match: " + routeDefinition.getId()); }
     */
  }
  /**
   * Validate the given handler against the current request.
   * <p>
   * The default implementation is empty. Can be overridden in subclasses, for example
   * to enforce specific preconditions expressed in URL mappings.
   * @param route the Route object to validate
   * @param exchange current exchange
   * @throws Exception if validation failed
   */
  @SuppressWarnings("UnusedParameters")
  protected void validateRoute(Route route, ServerWebExchange exchange) {
  }
  protected String getSimpleName() {
    return "RoutePredicateHandlerMapping";
  }
  public enum ManagementPortType {
    /**
     * The management port has been disabled.
     */
    DISABLED,
    /**
     * The management port is the same as the server port.
     */
    SAME,
    /**
     * The management port and server port are different.
     */
    DIFFERENT;
  }
}
目录
相关文章
|
8月前
|
算法 测试技术 C语言
深入理解HTTP/2:nghttp2库源码解析及客户端实现示例
通过解析nghttp2库的源码和实现一个简单的HTTP/2客户端示例,本文详细介绍了HTTP/2的关键特性和nghttp2的核心实现。了解这些内容可以帮助开发者更好地理解HTTP/2协议,提高Web应用的性能和用户体验。对于实际开发中的应用,可以根据需要进一步优化和扩展代码,以满足具体需求。
829 29
|
8月前
|
前端开发 数据安全/隐私保护 CDN
二次元聚合短视频解析去水印系统源码
二次元聚合短视频解析去水印系统源码
331 4
|
8月前
|
JavaScript 算法 前端开发
JS数组操作方法全景图,全网最全构建完整知识网络!js数组操作方法全集(实现筛选转换、随机排序洗牌算法、复杂数据处理统计等情景详解,附大量源码和易错点解析)
这些方法提供了对数组的全面操作,包括搜索、遍历、转换和聚合等。通过分为原地操作方法、非原地操作方法和其他方法便于您理解和记忆,并熟悉他们各自的使用方法与使用范围。详细的案例与进阶使用,方便您理解数组操作的底层原理。链式调用的几个案例,让您玩转数组操作。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
移动开发 前端开发 JavaScript
从入门到精通:H5游戏源码开发技术全解析与未来趋势洞察
H5游戏凭借其跨平台、易传播和开发成本低的优势,近年来发展迅猛。接下来,让我们深入了解 H5 游戏源码开发的技术教程以及未来的发展趋势。
|
8月前
|
存储 前端开发 JavaScript
在线教育网课系统源码开发指南:功能设计与技术实现深度解析
在线教育网课系统是近年来发展迅猛的教育形式的核心载体,具备用户管理、课程管理、教学互动、学习评估等功能。本文从功能和技术两方面解析其源码开发,涵盖前端(HTML5、CSS3、JavaScript等)、后端(Java、Python等)、流媒体及云计算技术,并强调安全性、稳定性和用户体验的重要性。
|
9月前
|
机器学习/深度学习 自然语言处理 算法
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
生成式 AI 大语言模型(LLMs)核心算法及源码解析:预训练篇
2348 1
|
9月前
|
前端开发 Java Nacos
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
本文介绍了如何使用Spring Cloud Alibaba 2023.0.0.0技术栈构建微服务网关,以应对微服务架构中流量治理与安全管控的复杂性。通过一个包含鉴权服务、文件服务和主服务的项目,详细讲解了网关的整合与功能开发。首先,通过统一路由配置,将所有请求集中到网关进行管理;其次,实现了限流防刷功能,防止恶意刷接口;最后,添加了登录鉴权机制,确保用户身份验证。整个过程结合Nacos注册中心,确保服务注册与配置管理的高效性。通过这些实践,帮助开发者更好地理解和应用微服务网关。
1703 0
🛡️Spring Boot 3 整合 Spring Cloud Gateway 工程实践
|
11月前
|
存储 JavaScript 开发工具
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
本次的.HarmonyOS Next ,ArkTS语言,HarmonyOS的元服务和DevEco Studio 开发工具,为开发者提供了构建现代化、轻量化、高性能应用的便捷方式。这些技术和工具将帮助开发者更好地适应未来的智能设备和服务提供方式。
基于HarmonyOS 5.0(NEXT)与SpringCloud架构的跨平台应用开发与服务集成研究【实战】
|
9月前
|
传感器 监控 安全
智慧工地云平台的技术架构解析:微服务+Spring Cloud如何支撑海量数据?
慧工地解决方案依托AI、物联网和BIM技术,实现对施工现场的全方位、立体化管理。通过规范施工、减少安全隐患、节省人力、降低运营成本,提升工地管理的安全性、效率和精益度。该方案适用于大型建筑、基础设施、房地产开发等场景,具备微服务架构、大数据与AI分析、物联网设备联网、多端协同等创新点,推动建筑行业向数字化、智能化转型。未来将融合5G、区块链等技术,助力智慧城市建设。
470 1
|
8月前
|
负载均衡 JavaScript 前端开发
分片上传技术全解析:原理、优势与应用(含简单实现源码)
分片上传通过将大文件分割成多个小的片段或块,然后并行或顺序地上传这些片段,从而提高上传效率和可靠性,特别适用于大文件的上传场景,尤其是在网络环境不佳时,分片上传能有效提高上传体验。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

推荐镜像

更多
  • DNS