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:///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;
}
}
Spring Cloud GateWay源码解析实战 - RoutePredicateHandlerMapping
原创公众号JavaEdge ©著作权
-
如何重写gorm日志(实现自定义慢sql打印)
gorm自定义日志格式,可实现慢sql自定义打印
sql SQL mysql -
【Spring Cloud】Dockerfile自定义镜像
常见的镜像在DockerHub就能找到,但是我们自己写的项目就必须自己构
spring cloud docker java java项目 -
spring cloud sleuth 自定义Mq traceId spring cloud gateway 自定义路由
文章目录前言谓词剖析实施自定义谓词工厂注册自定义谓语工厂使用自定义谓词1.使用Fluent API定义2.在YAML中定义测试[Spring Cloud 相关系列文章目录]()网关服务Spring Cloud Gateway 本文Spring Cloud Gateway 版本:2020.0.0前言之前讲过了Spring Cloud Gateway内置的11种路由谓词工厂,但是有些场景,还是不够我
spring boot java spring cloud Cloud 自定义 -
spring 自动装配自定义包
一、spring bean的自动装配 上次我们学到spring bean的注入方式,set属性注入和构造器注入,这节我们一起谈谈spring bean的自动装配,一共有三种方式byName,byType,constructor Spring IOC 容器可以自动装配 Bean. 需要做的仅仅是在 <bean> 的 autowire 属性里指定自动装配的模式 • byName根据名
spring 自动装配自定义包 spring bean的自动装配 bean的byName装配 bean的byType装配 spring IOC优点和缺点 -
Python三种模块导入方式详解 - 初学者必备教程
方式会导入模块中所有公共名称,容易导致命名冲突和代码可读性问题,应尽量避免在生产代码中使用。• 重复导入:Python会缓存已导入的模块。
#python 代码示例 基本语法 Python
















