spring gateway自定义局部Filter(GatewayFilter) AbstractGatewayFilterFactory不生效问题
文章目录一、示例二、问题出在哪?总结一、示例自定义的GatewayFilterPreviewGatewayFilterFactory.java/*** @author QLZ* @date 2021/6/29*/@Component@Slf4jpublic class PreviewGatewayFilterFactory extends AbstractGatewayFilterFactory&
前言
前一阵业务需求所以自定义了一个GatewayFilter,然后发现在我开启对应服务的时候,它不经过我自定义的GatewayFilter,在我停掉对应服务后,就会进入自定义的GatewayFilter。几经研究发现了问题,特此记录。
一、示例
自定义的GatewayFilter
PreviewGatewayFilterFactory.java
/**
* @author QLZ
* @date 2021/6/29
*/
@Component
@Slf4j
public class PreviewGatewayFilterFactory extends AbstractGatewayFilterFactory<PreviewGatewayFilterFactory.Config> {
public PreviewGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Lists.newArrayList("enabled");
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
log.info("每次路由匹配到会执行");
Boolean enabled = config.getEnabled();
log.info("从配置文件中获取到的 enabled 的值=[{}].", enabled);
return chain.filter(exchange);
};
}
@Data
public static class Config {
private Boolean enabled;
}
}
在路由中设置filters
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true #使用小写service-id
routes: #配置路由路径
- id: wallpaper-portal
uri: lb://wallpaper-portal
predicates:
- Path=/wallpaper-portal/**
filters:
- Preview=true
- StripPrefix=1
二、问题出在哪?
正常情况下按照上述代码编写和配置后,请求对应的URL就会进入自定义的PreviewGatewayFilterFactory 过滤器,而没有进入的原因是因为开启了
spring:
cloud:
gateway:
discovery:
locator:
enabled: true
开启此配置表示,gateway可以在注册中心(如:nacos)中根据服务id自动创建路由规则。而不经过我们手动配置的路由规则。换句话说就是开启了这个功能,实际上就可以不用在配置文件里写routes配置路由路径了。而带来的问题就是,它无法适配我们自己写的filter和predicate。
源码:
GatewayDiscoveryClientAutoConfiguration.java
public class GatewayDiscoveryClientAutoConfiguration {
public static List<PredicateDefinition> initPredicates() {
ArrayList<PredicateDefinition> definitions = new ArrayList<>();
// TODO: add a predicate that matches the url at /serviceId?
// add a predicate that matches the url at /serviceId/**
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(normalizeRoutePredicateName(PathRoutePredicateFactory.class));
predicate.addArg(PATTERN_KEY, "'/'+serviceId+'/**'");
definitions.add(predicate);
return definitions;
}
public static List<FilterDefinition> initFilters() {
ArrayList<FilterDefinition> definitions = new ArrayList<>();
// add a filter that removes /serviceId by default
FilterDefinition filter = new FilterDefinition();
filter.setName(normalizeFilterFactoryName(RewritePathGatewayFilterFactory.class));
String regex = "'/' + serviceId + '/(?<remaining>.*)'";
String replacement = "'/${remaining}'";
filter.addArg(REGEXP_KEY, regex);
filter.addArg(REPLACEMENT_KEY, replacement);
definitions.add(filter);
return definitions;
}
@Bean
public DiscoveryLocatorProperties discoveryLocatorProperties() {
DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
properties.setPredicates(initPredicates());
properties.setFilters(initFilters());
return properties;
}
....//省略若干代码
@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(value = "spring.cloud.discovery.reactive.enabled",
matchIfMissing = true)
public static class ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration {
@Bean
//如果为true则创建此bean
@ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
ReactiveDiscoveryClient discoveryClient,
DiscoveryLocatorProperties properties) {
return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
}
}
}
DiscoveryClientRouteDefinitionLocator.java
public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {
private static final Log log = LogFactory
.getLog(DiscoveryClientRouteDefinitionLocator.class);
private final DiscoveryLocatorProperties properties;
private final String routeIdPrefix;
private final SimpleEvaluationContext evalCtxt;
private Flux<List<ServiceInstance>> serviceInstances;
public DiscoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient,
DiscoveryLocatorProperties properties) {
this(discoveryClient.getClass().getSimpleName(), properties);
serviceInstances = discoveryClient.getServices()
.flatMap(service -> discoveryClient.getInstances(service).collectList());
}
private DiscoveryClientRouteDefinitionLocator(String discoveryClientName,
DiscoveryLocatorProperties properties) {
this.properties = properties;
if (StringUtils.hasText(properties.getRouteIdPrefix())) {
routeIdPrefix = properties.getRouteIdPrefix();
}
else {
routeIdPrefix = discoveryClientName + "_";
}
evalCtxt = SimpleEvaluationContext.forReadOnlyDataBinding().withInstanceMethods()
.build();
}
@Override
public Flux<RouteDefinition> getRouteDefinitions() {
...//省略若干代码
return serviceInstances.filter(instances -> !instances.isEmpty())
.map(instances -> instances.get(0)).filter(includePredicate)
.map(instance -> {
RouteDefinition routeDefinition = buildRouteDefinition(urlExpr,
instance);
final ServiceInstance instanceForEval = new DelegatingServiceInstance(
instance, properties);
//设置断言
for (PredicateDefinition original : this.properties.getPredicates()) {
PredicateDefinition predicate = new PredicateDefinition();
predicate.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs()
.entrySet()) {
String value = getValueFromExpr(evalCtxt, parser,
instanceForEval, entry);
predicate.addArg(entry.getKey(), value);
}
routeDefinition.getPredicates().add(predicate);
}
//设置过滤器
for (FilterDefinition original : this.properties.getFilters()) {
FilterDefinition filter = new FilterDefinition();
filter.setName(original.getName());
for (Map.Entry<String, String> entry : original.getArgs()
.entrySet()) {
String value = getValueFromExpr(evalCtxt, parser,
instanceForEval, entry);
filter.addArg(entry.getKey(), value);
}
routeDefinition.getFilters().add(filter);
}
return routeDefinition;
});
}
}
看源码可知,开启spring.cloud.gateway.discovery.locator.enabled=true后,创建
DiscoveryClientRouteDefinitionLocator对象,此对象仅包含一个PathRoutePredicateFactory.class类型的Predicate 和 RewritePathGatewayFilterFactory.class类型的filter。并不会包含进自定义的filter。所以才会无效。
总结
spring.cloud.gateway.discovery.locator.enabled=false后,自定义的gateway filter才会生效。
更多推荐
所有评论(0)