springcloudspring cloud gateway

springcloud gateway自定义路由

2022-11-27  本文已影响0人  virtual灬zzZ

一般来说,定义路由只需要在配置文件yml中进行编写,或者使用配置类进行编写。

yml例子:

spring:
  cloud:
    gateway:
      routes: 
        - id: test
          uri: http://192.168.1.106:8000
          predicates:
            - Path=/cs/** 
          filters: # 网关过滤器
            - StripPrefix=1

代码配置类:

import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class TestRoute {

    @Bean
    public RouteLocator routeLocatorBuilder(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("test",
                p -> p.path("/cs/**")
                        .filters(f -> f.stripPrefix(1))
                        .uri("http://192.168.1.106:8000"))
                //追加
                //.route()
                .build();
    }
}

spring cloud gateway访问微服务

spring:
  application:
    name: gateway-server
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          enabled: true

enabled=true,表明使用服务名进行调用,如http://localhost:9000/otherService/test,9000是gateway端口,otherService是其他微服务,test是其他微服务的接口。

同时我们可以自己定制化,设置成false,再如上 自定义访问地址。

访问地址注意事项

在gateway中配置uri配置有三种方式,包括
第一种:ws(websocket)方式: uri: ws://localhost:9000
第二种:http方式: uri: http://localhost:8130/
第三种:lb(注册中心中服务名字)方式: uri: lb://brilliance-consumer

其中ws和http方式不容易出错,因为http格式比较固定,但是lb方式比较灵活自由。不考虑网关,只考虑服务时,服务名命名时比较自由,都能启动被访问,被注册到注册中心,但是如果提供给gateway使用时,就会对服务命名方式有特殊要求了。
能被gateway的lb方式识别到的命名规则为:

"[a-zA-Z]([a-zA-Z]|\\d|\\+|\\.|-)*:.*"

这也意味着,java命名规范中可以使用的英文下划线("_")不能被识别,而我命名为:brilliance_consumer,刚好带下划线,改为brilliance-consumer后则可以正常通过网关访问自己项目。
如果名字中有非“a-zA-Z:.”规则字符,则会报错,
规则见包org.springframework.cloud.gateway.filter中的类RouteToRequestUrlFilter:

动态路由

gateway加载路由配置信息流程
1 路由初始化

无论是yml还是代码,这些配置最终都是被封装到RouteDefinition对象中。

image

一个RouteDefinition有个唯一的ID,如果不指定,就默认是UUID,多个RouteDefinition组成了gateway的路由系统。

所有路由信息在系统启动时就被加载装配好了,并存到了内存里。我们从源码来看看。

圆圈里就是装配yml文件的,它返回的是PropertiesRouteDefinitionLocator,该类继承了RouteDefinitionLocator,RouteDefinitionLocator就是路由的装载器,里面只有一个方法,就是获取路由信息的。该接口有多个实现类,分别对应不同方式配置的路由方式。

通过这几个实现类,再结合上面的AutoConfiguration里面的Primary信息,就知道加载配置信息的顺序。

PropertiesRouteDefinitionLocator-->|配置文件加载初始化| CompositeRouteDefinitionLocator RouteDefinitionRepository-->|存储器中加载初始化| CompositeRouteDefinitionLocator DiscoveryClientRouteDefinitionLocator-->|注册中心加载初始化| CompositeRouteDefinitionLocator

这是第一顺序,就是从CachingRouteLocator中获取路由信息,我们可以打开该类进行验证。

不管发起什么请求,必然会走上面的断点处。请求一次,走一次。这是将路由信息缓存到了Map中。配置信息一旦请求过一次,就会被缓存到上图的CachingRouteLocator类中,再次发起请求后,会直接从map中读取。

如果想动态刷新配置信息,就需要发起一个RefreshRoutesEvent的事件,上图的cache会监听该事件,并重新拉取路由配置信息。

通过下图,可以看到如果没有RouteDefinitionRepository的实例,则默认用InMemoryRouteDefinitionRepository。而做动态路由的关键就在这里。即通过自定义的RouteDefinitionRepository类,来提供路由配置信息。

例如:

在getRouteDefinitions方法返回你自定义的路由配置信息即可。这里可以用数据库、nosql等等任意你喜欢的方式来提供。而且配置信息修改后,发起一次RefreshRoutesEvent事件即可让配置生效。

实现,采用consul配置中心

①:监听RefreshRoutesEvent事件,只要别的服务上线或者下线,都会触发该事件。

@EventListener(RefreshRoutesEvent.class)

②:读取discoveryClient,即读取配置中心的服务,该类是通用类,配置中心如consul、eureka相关的类都会实现它。

 List<String> services = discoveryClient.getServices().stream().collect(Collectors.toList());

③ 引入RouteDefinitionWriter ,其实际是InMemoryRouteDefinitionRepository,提供了save和delete路由方法。

routeDefinitionWriter.delete(Mono.just(routeId)).subscribe();

routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();

参考:
详解SpringCloud-gateway动态路由两种方式,以及路由加载过程

Spring Cloud Gateway 多种思路实现动态路由

上一篇 下一篇

猜你喜欢

热点阅读