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;
  }
}
目录
相关文章
|
1月前
|
缓存 安全 Java
Spring Security通用权限管理模型解析
Spring Security作为Spring生态的核心安全框架,结合RBAC与ACL权限模型,基于IoC与AOP构建灵活、可扩展的企业级权限控制体系,涵盖认证、授权流程及数据库设计、性能优化等实现策略。
152 0
|
1月前
|
缓存 安全 Java
Spring Security权限管理解析
Spring Security是Spring生态中的核心安全框架,采用认证与授权分离架构,提供高度可定制的权限管理方案。其基于过滤器链实现认证流程,通过SecurityContextHolder管理用户状态,并结合RBAC模型与动态权限决策,支持细粒度访问控制。通过扩展点如自定义投票器、注解式校验与前端标签,可灵活适配多租户、API网关等复杂场景。结合缓存优化与无状态设计,适用于高并发与前后端分离架构。
159 0
|
1月前
|
人工智能 Java 开发者
【Spring】原理解析:Spring Boot 自动配置
Spring Boot通过“约定优于配置”的设计理念,自动检测项目依赖并根据这些依赖自动装配相应的Bean,从而解放开发者从繁琐的配置工作中解脱出来,专注于业务逻辑实现。
|
1月前
|
SQL Java 数据库连接
Spring Data JPA 技术深度解析与应用指南
本文档全面介绍 Spring Data JPA 的核心概念、技术原理和实际应用。作为 Spring 生态系统中数据访问层的关键组件,Spring Data JPA 极大简化了 Java 持久层开发。本文将深入探讨其架构设计、核心接口、查询派生机制、事务管理以及与 Spring 框架的集成方式,并通过实际示例展示如何高效地使用这一技术。本文档约1500字,适合有一定 Spring 和 JPA 基础的开发者阅读。
210 0
|
11天前
|
设计模式 前端开发 Java
《深入理解Spring》:Spring MVC架构深度解析与实践
Spring MVC是基于Spring框架的Web开发核心模块,实现Model-View-Controller设计模式。它通过DispatcherServlet统一调度请求,结合注解驱动的控制器、灵活的数据绑定与验证、丰富的视图支持及拦截器、异常处理等机制,提升开发效率与系统可维护性,助力构建高性能、易测试的现代Web应用。
|
11天前
|
XML Java 数据格式
《深入理解Spring》:AOP面向切面编程深度解析
Spring AOP通过代理模式实现面向切面编程,将日志、事务等横切关注点与业务逻辑分离。支持注解、XML和编程式配置,提供五种通知类型及丰富切点表达式,助力构建高内聚、低耦合的可维护系统。
|
11天前
|
前端开发 Java 微服务
《深入理解Spring》:Spring、Spring MVC与Spring Boot的深度解析
Spring Framework是Java生态的基石,提供IoC、AOP等核心功能;Spring MVC基于其构建,实现Web层MVC架构;Spring Boot则通过自动配置和内嵌服务器,极大简化了开发与部署。三者层层演进,Spring Boot并非替代,而是对前者的高效封装与增强,适用于微服务与快速开发,而深入理解Spring Framework有助于更好驾驭整体技术栈。
|
1月前
|
Java 数据库 数据安全/隐私保护
Spring Boot四层架构深度解析
本文详解Spring Boot四层架构(Controller-Service-DAO-Database)的核心思想与实战应用,涵盖职责划分、代码结构、依赖注入、事务管理及常见问题解决方案,助力构建高内聚、低耦合的企业级应用。
530 1
|
1月前
|
Kubernetes Java 微服务
Spring Cloud 微服务架构技术解析与实践指南
本文档全面介绍 Spring Cloud 微服务架构的核心组件、设计理念和实现方案。作为构建分布式系统的综合工具箱,Spring Cloud 为微服务架构提供了服务发现、配置管理、负载均衡、熔断器等关键功能的标准化实现。本文将深入探讨其核心组件的工作原理、集成方式以及在实际项目中的最佳实践,帮助开发者构建高可用、可扩展的分布式系统。
308 0
|
1月前
|
安全 Java 数据安全/隐私保护
Spring Security 核心技术解析与实践指南
本文档深入探讨 Spring Security 框架的核心架构、关键组件和实际应用。作为 Spring 生态系统中负责安全认证与授权的关键组件,Spring Security 为 Java 应用程序提供了全面的安全服务。本文将系统介绍其认证机制、授权模型、过滤器链原理、OAuth2 集成以及最佳实践,帮助开发者构建安全可靠的企业级应用。
122 0

热门文章

最新文章

推荐镜像

更多
  • DNS