前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊spring cloud的DiscoveryClientRouteDefinitionLocator

聊聊spring cloud的DiscoveryClientRouteDefinitionLocator

作者头像
code4it
发布2018-09-17 16:47:07
1.7K0
发布2018-09-17 16:47:07
举报
文章被收录于专栏:码匠的流水账码匠的流水账

本文主要研究一下spring cloud的DiscoveryClient Route Definition Locator

GatewayAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/config/GatewayAutoConfiguration.java

代码语言:javascript
复制
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@EnableConfigurationProperties
@AutoConfigureBefore(HttpHandlerAutoConfiguration.class)
@AutoConfigureAfter({GatewayLoadBalancerClientAutoConfiguration.class, GatewayClassPathWarningAutoConfiguration.class})
@ConditionalOnClass(DispatcherHandler.class)
public class GatewayAutoConfiguration {
    //......
    @Bean
    @ConditionalOnMissingBean
    public PropertiesRouteDefinitionLocator propertiesRouteDefinitionLocator(GatewayProperties properties) {
        return new PropertiesRouteDefinitionLocator(properties);
    }

    @Bean
    @ConditionalOnMissingBean(RouteDefinitionRepository.class)
    public InMemoryRouteDefinitionRepository inMemoryRouteDefinitionRepository() {
        return new InMemoryRouteDefinitionRepository();
    }
    @Bean
    @Primary
    public RouteDefinitionLocator routeDefinitionLocator(List<RouteDefinitionLocator> routeDefinitionLocators) {
        return new CompositeRouteDefinitionLocator(Flux.fromIterable(routeDefinitionLocators));
    }
    //......
}

这里注册了CompositeRouteDefinitionLocator

GatewayDiscoveryClientAutoConfiguration

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/discovery/GatewayDiscoveryClientAutoConfiguration.java

代码语言:javascript
复制
@Configuration
@ConditionalOnProperty(name = "spring.cloud.gateway.enabled", matchIfMissing = true)
@AutoConfigureBefore(GatewayAutoConfiguration.class)
@ConditionalOnClass({DispatcherHandler.class, DiscoveryClient.class})
@EnableConfigurationProperties
public class GatewayDiscoveryClientAutoConfiguration {

    @Bean
    @ConditionalOnBean(DiscoveryClient.class)
    @ConditionalOnProperty(name = "spring.cloud.gateway.discovery.locator.enabled")
    public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(
            DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
    }

    @Bean
    public DiscoveryLocatorProperties discoveryLocatorProperties() {
        DiscoveryLocatorProperties properties = new DiscoveryLocatorProperties();
        properties.setPredicates(initPredicates());
        properties.setFilters(initFilters());
        return properties;
    }

    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;
    }

}

默认配置了一个根据serviceId进行rewrite的filter

DiscoveryLocatorProperties

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/discovery/DiscoveryLocatorProperties.java

代码语言:javascript
复制
@ConfigurationProperties("spring.cloud.gateway.discovery.locator")
public class DiscoveryLocatorProperties {

    /** Flag that enables DiscoveryClient gateway integration */
    private boolean enabled = false;

    /**
     * The prefix for the routeId, defaults to discoveryClient.getClass().getSimpleName() + "_".
     * Service Id will be appended to create the routeId.
     */
    private String routeIdPrefix;

    /**
     * SpEL expression that will evaluate whether to include a service in gateway integration or not,
     * defaults to: true
     */
    private String includeExpression = "true";

    /** SpEL expression that create the uri for each route, defaults to: 'lb://'+serviceId */
    private String urlExpression = "'lb://'+serviceId";

    /**
     * Option to lower case serviceId in predicates and filters, defaults to false.
     * Useful with eureka when it automatically uppercases serviceId.
     * so MYSERIVCE, would match /myservice/**
     */
    private boolean lowerCaseServiceId = false;

    private List<PredicateDefinition> predicates = new ArrayList<>();

    private List<FilterDefinition> filters = new ArrayList<>();

    //......

    @Override
    public String toString() {
        return new ToStringCreator(this)
                .append("enabled", enabled)
                .append("routeIdPrefix", routeIdPrefix)
                .append("includeExpression", includeExpression)
                .append("urlExpression", urlExpression)
                .append("lowerCaseServiceId", lowerCaseServiceId)
                .append("predicates", predicates)
                .append("filters", filters)
                .toString();
    }
}
  • 默认lowerCaseServiceId为false,因为eureka默认把serviceId大写
  • urlExpression默认为’lb://‘+serviceId

DiscoveryClientRouteDefinitionLocator

spring-cloud-gateway-core-2.0.0.RC2-sources.jar!/org/springframework/cloud/gateway/discovery/DiscoveryClientRouteDefinitionLocator.java

代码语言:javascript
复制
public class DiscoveryClientRouteDefinitionLocator implements RouteDefinitionLocator {

    private final DiscoveryClient discoveryClient;
    private final DiscoveryLocatorProperties properties;
    private final String routeIdPrefix;

    public DiscoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
        this.discoveryClient = discoveryClient;
        this.properties = properties;
        if (StringUtils.hasText(properties.getRouteIdPrefix())) {
            this.routeIdPrefix = properties.getRouteIdPrefix();
        } else {
            this.routeIdPrefix = this.discoveryClient.getClass().getSimpleName() + "_";
        }
    }

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        SimpleEvaluationContext evalCtxt = SimpleEvaluationContext
                .forReadOnlyDataBinding()
                .withInstanceMethods()
                .build();

        SpelExpressionParser parser = new SpelExpressionParser();
        Expression includeExpr = parser.parseExpression(properties.getIncludeExpression());
        Expression urlExpr = parser.parseExpression(properties.getUrlExpression());

        return Flux.fromIterable(discoveryClient.getServices())
                .map(discoveryClient::getInstances)
                .filter(instances -> !instances.isEmpty())
                .map(instances -> instances.get(0))
                .filter(instance -> {
                    Boolean include = includeExpr.getValue(evalCtxt, instance, Boolean.class);
                    if (include == null) {
                        return false;
                    }
                    return include;
                })
                .map(instance -> {
                    String serviceId = instance.getServiceId();

                    RouteDefinition routeDefinition = new RouteDefinition();
                    routeDefinition.setId(this.routeIdPrefix + serviceId);
                    String uri = urlExpr.getValue(evalCtxt, instance, String.class);
                    routeDefinition.setUri(URI.create(uri));

                    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;
                });
    }

    String getValueFromExpr(SimpleEvaluationContext evalCtxt, SpelExpressionParser parser, ServiceInstance instance, Map.Entry<String, String> entry) {
        Expression valueExpr = parser.parseExpression(entry.getValue());
        return valueExpr.getValue(evalCtxt, instance, String.class);
    }
    //......
}

可以看到这里从discoveryClient.getServices()获取注册信息转换为RouteDefinition

小结

RouteDefinitionLocator接口有不同的实现类:

  • InMemoryRouteDefinitionRepository
  • CompositeRouteDefinitionLocator
  • DiscoveryClientRouteDefinitionLocator
  • PropertiesRouteDefinitionLocator
  • CachingRouteDefinitionLocator 如果开启spring.cloud.gateway.discovery.locator.enabled=true,那么最后CompositeRouteDefinitionLocator则是组合了InMemoryRouteDefinitionRepository、PropertiesRouteDefinitionLocator、DiscoveryClientRouteDefinitionLocator三个RouteDefinitionLocator

doc

  • 114.2 DiscoveryClient Route Definition Locator
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-06-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码匠的流水账 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • GatewayAutoConfiguration
  • GatewayDiscoveryClientAutoConfiguration
  • DiscoveryLocatorProperties
  • DiscoveryClientRouteDefinitionLocator
  • 小结
  • doc
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档