SpringCloudGateway開發(fā)過程解析
路由簡介:
1.SpringCloudGateWay 是用于替代zuul作為API網(wǎng)關(guān),在gateway中有三個(gè)重要的名詞:過濾器,斷言,路由
過濾器與斷言是路由的一部分,路由便是將請(qǐng)求進(jìn)行一系列的處理后分發(fā)到各個(gè)服務(wù)的一個(gè)過程。
路由的過程:首先會(huì)加載斷言以及路由,在接受到請(qǐng)求后根據(jù)斷言加載的順序會(huì)匹配到先加載的斷言,只有與斷言匹配了的請(qǐng)求才會(huì)進(jìn)入路由,沒有匹配到的服務(wù)會(huì)將請(qǐng)求當(dāng)成普通的訪問請(qǐng)求。
2:路由加載斷言的方式:
斷言加載的方式有四種,分別是配置文件,java編碼,數(shù)據(jù)庫以及注冊(cè)中心
第一種配置文件:
在官方文檔中主要介紹的就是配置文件的加載方式
官方地址:https://cloud.spring.io/spring-cloud-gateway/reference/html/#gateway-starter
一般的斷言有三種要素:id,uri,predicate.
id是斷言的標(biāo)識(shí),uri是ip+端口,predicate則是斷言匹配的規(guī)則
3:示例:
新建一個(gè)springboot項(xiàng)目,并且引入springcloudgateway的依賴
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> </dependencies>
在啟動(dòng)類注冊(cè)三個(gè)全局過濾器
@SpringBootApplication public class GateWayApplication { public static void main(String[] args) { SpringApplication.run(GateWayApplication.class, args); } @Bean @Order(-1) public GlobalFilter a() { return (exchange, chain) -> { return chain.filter(exchange).then(Mono.fromRunnable(() -> { System.out.println(-1); })); }; } @Bean @Order(0) public GlobalFilter b() { return (exchange, chain) -> { return chain.filter(exchange).then(Mono.fromRunnable(() -> { System.out.println(0); })); }; } @Bean @Order(1) public GlobalFilter c() { return (exchange, chain) -> { return chain.filter(exchange).then(Mono.fromRunnable(() -> { System.out.println(1); })); }; } }
在配置文件類配置兩條路由
server.port: 7777 spring: application: name: gateway cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true routes: - id: method_route uri: http://127.0.0.1:9999 predicates: - Method=GET - id: method_route uri: http://127.0.0.1:8006 predicates: - Method=GET
發(fā)送請(qǐng)求,請(qǐng)求到達(dá)后匹配的是第一條路由,由此可以知道路由匹配的順序會(huì)根據(jù)加載的順序來
4:SpringCloudGateWay從注冊(cè)中心獲得路由
在官方文檔中,我們可以看到有這樣的一段話
Configuring Predicates and Filters For DiscoveryClient Routes
By default the Gateway defines a single predicate and filter for routes created via a DiscoveryClient.
The default predicate is a path predicate defined with the pattern /serviceId/**, where serviceId is the id of the service from the DiscoveryClient.
The default filter is rewrite path filter with the regex /serviceId/(?<remaining>.*) and the replacement /${remaining}. This just strips the service id from the path before the request is sent downstream.
If you would like to customize the predicates and/or filters used by the DiscoveryClient routes you can do so by setting spring.cloud.gateway.discovery.locator.predicates[x] and spring.cloud.gateway.discovery.locator.filters[y]. When doing so you need to make sure to include the default predicate and filter above, if you want to retain that functionality. Below is an example of what this looks like.
地址 :https://cloud.spring.io/spring-cloud-gateway/reference/html/#_global_filters
spring.cloud.gateway.discovery.locator.predicates[0].name: Path spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'" spring.cloud.gateway.discovery.locator.predicates[1].name: Host spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'" spring.cloud.gateway.discovery.locator.filters[0].name: Hystrix spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/(?<remaining>.*)'" spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
根據(jù)文檔介紹,依照這種方式,可以從注冊(cè)中心獲得斷言與過濾器的配置
5:SpringGateWay從數(shù)據(jù)庫配置路由
public class DBRouteDefinitionRepository implements RouteDefinitionRepository
項(xiàng)目中實(shí)現(xiàn)了RouteDefinitionRepository后,springgateway會(huì)采用你實(shí)現(xiàn)的這個(gè)類去加載路由,如果不實(shí)現(xiàn)則采用他默認(rèn)的方式加載路由
public class DBRouteDefinitionRepository implements RouteDefinitionRepository { //保存路由 private final Map<String, RouteDefinition> routes = synchronizedMap(new LinkedHashMap<String, RouteDefinition>()); private Logger log = LoggerFactory.getLogger(DBRouteDefinitionRepository.class); //初始標(biāo)準(zhǔn) private boolean init_flag = true; // private final GatewayProperties properties; private DynamicRouteServiceImpl service; public DBRouteDefinitionRepository(GatewayProperties properties) { this.properties = properties; this.service = new DynamicRouteServiceImpl(); } @Override public Flux<RouteDefinition> getRouteDefinitions() { if(init_flag) { List<RouteDefinition> routeDefinitions = new ArrayList<>(); List<RouteDefinition> rs = new ArrayList<>(); try { routeDefinitions = service.quertAllRoutes();//從數(shù)據(jù)庫中加載route rs = this.properties.getRoutes();//獲得配置文件的route for (RouteDefinition rse : rs) { routeDefinitions.add(rse); } routes.clear(); routeDefinitions.forEach(x->routes.put(x.getId(), x)); init_flag=false; } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); log.error("Init Route Fail,Can't get Routes.",e); } return Flux.fromIterable(routeDefinitions); }else { return Flux.fromIterable(routes.values()); } } @Override public Mono<Void> delete(Mono<String> routeId) { return routeId.flatMap(id -> { if (routes.containsKey(id)) { routes.remove(id); return Mono.empty(); } return Mono.defer(() -> Mono.error(new NotFoundException("RouteDefinition not found: "+routeId))); }); } @Override public Mono<Void> save(Mono<RouteDefinition> route) { return route.flatMap( r -> { routes.put(r.getId(), r); return Mono.empty(); }); } }
這個(gè)是我自己實(shí)現(xiàn)的類,這個(gè)類可以從數(shù)據(jù)庫與配置文件中獲得路由配置,從數(shù)據(jù)庫中獲得路由配置可以根據(jù)個(gè)人的要求來
@Validated public class RouteDefinition { @NotEmpty private String id = UUID.randomUUID().toString(); @NotEmpty @Valid private List<PredicateDefinition> predicates = new ArrayList<>(); @Valid private List<FilterDefinition> filters = new ArrayList<>(); @NotNull private URI uri; private int order = 0; public RouteDefinition() { } public RouteDefinition(String text) { int eqIdx = text.indexOf('='); if (eqIdx <= 0) { throw new ValidationException("Unable to parse RouteDefinition text '" + text + "'" + ", must be of the form name=value"); } setId(text.substring(0, eqIdx)); String[] args = tokenizeToStringArray(text.substring(eqIdx + 1), ","); setUri(URI.create(args[0])); for (int i = 1; i < args.length; i++) { this.predicates.add(new PredicateDefinition(args[i])); } } public String getId() { return id; } public void setId(String id) { this.id = id; } public List<PredicateDefinition> getPredicates() { return predicates; } public void setPredicates(List<PredicateDefinition> predicates) { this.predicates = predicates; } public List<FilterDefinition> getFilters() { return filters; } public void setFilters(List<FilterDefinition> filters) { this.filters = filters; } public URI getUri() { return uri; } public void setUri(URI uri) { this.uri = uri; } public int getOrder() { return order; } public void setOrder(int order) { this.order = order; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } RouteDefinition routeDefinition = (RouteDefinition) o; return Objects.equals(id, routeDefinition.id) && Objects.equals(predicates, routeDefinition.predicates) && Objects.equals(order, routeDefinition.order) && Objects.equals(uri, routeDefinition.uri); } @Override public int hashCode() { return Objects.hash(id, predicates, uri); } @Override public String toString() { return "RouteDefinition{" + "id='" + id + '\'' + ", predicates=" + predicates + ", filters=" + filters + ", uri=" + uri + ", order=" + order + '}'; } }
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- SpringCloudGateway?Nacos?GitlabRunner全自動(dòng)灰度服務(wù)搭建發(fā)布
- 基于SpringCloudGateway實(shí)現(xiàn)微服務(wù)網(wǎng)關(guān)的方式
- 詳解SpringCloudGateway內(nèi)存泄漏問題
- SpringCloud Gateway動(dòng)態(tài)路由配置詳解
- springcloud-gateway集成knife4j的示例詳解
- SpringCloud Gateway實(shí)現(xiàn)限流功能詳解
- SpringCloudGateway使用Skywalking時(shí)日志打印traceId解析
相關(guān)文章
關(guān)于kafka-consumer-offset位移問題
這篇文章主要介紹了關(guān)于kafka-consumer-offset位移問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Java設(shè)計(jì)模式以虹貓藍(lán)兔的故事講解適配器模式
適配器模式(Adapter?Pattern)是作為兩個(gè)不兼容的接口之間的橋梁。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它結(jié)合了兩個(gè)獨(dú)立接口的功能2022-04-04通過實(shí)例解析synchronized和lock區(qū)別
這篇文章主要介紹了通過實(shí)例解析synchronized和lock區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-12-12關(guān)于PreparedStatement的setObject作用及說明
這篇文章主要介紹了關(guān)于PreparedStatement的setObject作用及說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Java Calendar類的使用總結(jié)實(shí)例
這篇文章主要介紹了Java Calendar類的使用總結(jié)實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03AndroidStudio無法新建Java工程的簡單解決辦法
AS創(chuàng)建java工程是非常麻煩的,AS沒有提供直接創(chuàng)建java工程的方法且常常無法新建,這篇文章主要給大家介紹了關(guān)于AndroidStudio無法新建Java工程的簡單解決辦法,需要的朋友可以參考下2024-06-06詳解SpringBoot開發(fā)案例之整合Dubbo分布式服務(wù)
這篇文章主要介紹了詳解SpringBoot開發(fā)案例之整合Dubbo分布式服務(wù),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-10-10