赞
踩
本文主要聊聊Spring Cloud Gateway(以下简称gateway,使用的版本是2.2.1.RELEASE),结合Nacos的注册中心,实现根据微服务名,自动路由到对应的微服务。在gateway的官网上,可以看到如下描述:
大致意思是,通过如下配置,可以实现自动根据服务发现为每一个服务创建了一个路由router,
这个router将以服务名开头的请求路径转发到对应的服务:
spring.cloud.gateway.discovery.locator.enabled=true
并且在很多博客中,也可以发现类似的说法:
spring.cloud.gateway.discovery.locator.enabled为true,表明gateway开启服务注册和发现的功能,并且spring cloud gateway自动根据服务发现为每一个服务创建了一个router,
这个router将以服务名开头的请求路径转发到对应的服务。
但是,我在测试中发现该配置并不起作用。在GitHub中也找到相关问题:
于是,找了很多资料去佐证,发现很少有人提及这个问题,但是并不是毫无进展,起码知道了spring.cloud.gateway.discovery.locator.enabled配置生效的地方是GatewayDiscoveryClientAutoConfiguration的静态内部类:
- @Configuration(
- proxyBeanMethods = false
- )
- @ConditionalOnProperty(
- value = {"spring.cloud.discovery.reactive.enabled"},
- matchIfMissing = true
- )
- public static class ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration {
- public ReactiveDiscoveryClientRouteDefinitionLocatorConfiguration() {
- }
-
- @Bean
- @ConditionalOnProperty(
- name = {"spring.cloud.gateway.discovery.locator.enabled"}
- )
- public DiscoveryClientRouteDefinitionLocator discoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
- return new DiscoveryClientRouteDefinitionLocator(discoveryClient, properties);
- }
- }
在这里,创建了DiscoveryClientRouteDefinitionLocator对象,DiscoveryClientRouteDefinitionLocator实现了RouteDefinitionLocator接口,该接口只有获取路由定义的方法:
- public interface RouteDefinitionLocator {
- Flux<RouteDefinition> getRouteDefinitions();
- }
DiscoveryClientRouteDefinitionLocator的实现,主要是对serviceInstances的操作:
而serviceInstances来源于构造函数:
- public DiscoveryClientRouteDefinitionLocator(ReactiveDiscoveryClient discoveryClient, DiscoveryLocatorProperties properties) {
- this(discoveryClient.getClass().getSimpleName(), properties);
- this.serviceInstances = discoveryClient.getServices().flatMap((service) -> {
- return discoveryClient.getInstances(service).collectList();
- });
- }
discoveryClient的实现类是ReactiveCompositeDiscoveryClient:
该方法确实实现了基于服务的路由创建:
但是ReactiveCompositeDiscoveryClient实现的接口是ReactiveDiscoveryClient,和NacosDiscoveryClient毫无关联,所谓它无法获取服务的注册列表,进而无法创建有效的路由。
既然配置不行,就只能自己实现RouteDefinitionLocator接口了:
- @Component
- public class MyRouteDefinitionLocator implements RouteDefinitionLocator {
-
- @Autowired
- private DiscoveryClient discoveryClient;
-
- @Value("${spring.application.name}")
- private String gatewayName;
-
- @Override
- public Flux<RouteDefinition> getRouteDefinitions() {
- // 服务发现
- List<String> serviceList = discoveryClient.getServices();
- System.out.println("serviceList = "+serviceList);
- // 只有网关服务,直接返回
- if (serviceList.size() < 2){
- return Flux.empty();
- }
- // 服务的个数
- int serviceNum = serviceList.size();
- if (serviceList.contains(gatewayName)){
- // 排除网关服务
- serviceNum--;
-
- }
- RouteDefinition[] routeDefinitions = new RouteDefinition[serviceNum];
- int count = 0;
- for (String service : serviceList) {
- if (service.equalsIgnoreCase(gatewayName)){
- continue;
- }
- RouteDefinition definition = new RouteDefinition();
- definition.setId(service);
- // 负载均衡
- definition.setUri(URI.create("lb://"+service));
- // 根据微服务名,进行路径匹配
- definition.setPredicates(Collections.singletonList(new PredicateDefinition("Path=/"+service+"/**")));
- // 去掉微服务名
- definition.setFilters(Collections.singletonList(new FilterDefinition("StripPrefix=1")));
- routeDefinitions[count++] = definition;
- }
- return Flux.just(routeDefinitions);
- }
- }
通过RouteDefinitionLocator接口,实现全量更新路由信息,达到根据微服务名动态路由到对应的微服务的目的。比如调用:
这里的端口是网关的端口,feign-consumer是注册到nacos的微服务名,则会根据微服务名路由到feign-consumer微服务。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。