一般来说,定义路由只需要在配置文件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();
网友评论