SpringCloudGateway开发详解

  1. 路由简介:

        SpringCloudGateWay 是用于替代zuul作为API网关,在gateway中有三个重要的名词:过滤器,断言,路由

      过滤器与断言是路由的一部分,路由便是将请求进行一系列的处理后分发到各个服务的一个过程。

      路由的过程:首先会加载断言以及路由,在接受到请求后根据断言加载的顺序会匹配到先加载的断言,只有与断言匹配了的请求才会进入路由,没有匹配到的服务会将请求当成普通的访问请求。

2:路由加载断言的方式:

      断言加载的方式有四种,分别是配置文件,java编码,数据库以及注册中心

      第一种配置文件:

            在官方文档中主要介绍的就是配置文件的加载方式

            官方地址:https://cloud.spring.io/spring-cloud-gateway/reference/html/#gateway-starter

                一般的断言有三种要素:id,uri,predicate.

            id是断言的标识,uri是ip+端口,predicate则是断言匹配的规则

  3:示例:

       新建一个springboot项目,并且引入springcloudgateway的依赖

复制代码
 1 <dependencies>
 3         <dependency>
 4             <groupId>org.springframework.boot</groupId>
 5             <artifactId>spring-boot-starter-test</artifactId>
 6             <scope>test</scope>
 7         </dependency>
 8         <dependency>
 9             <groupId>org.springframework.cloud</groupId>
10             <artifactId>spring-cloud-starter-gateway</artifactId>
11         </dependency>
12     </dependencies>
复制代码

      在启动类注册三个全局过滤器

复制代码
 1 @SpringBootApplication
 2 public class GateWayApplication {
 3 
 4     public static void main(String[] args) {
 5         SpringApplication.run(GateWayApplication.class, args);
 6     }
 7 
 8     @Bean
 9     @Order(-1)
10     public GlobalFilter a() {
11         return (exchange, chain) -> {
12 
13             return chain.filter(exchange).then(Mono.fromRunnable(() -> {
14                 System.out.println(-1);
15             }));
16         };
17     }
18 
19     @Bean
20     @Order(0)
21     public GlobalFilter b() {
22         return (exchange, chain) -> {
23 
24             return chain.filter(exchange).then(Mono.fromRunnable(() -> {
25                 System.out.println(0);
26             }));
27         };
28     }
29 
30     @Bean
31     @Order(1)
32     public GlobalFilter c() {
33         return (exchange, chain) -> {
34 
35             return chain.filter(exchange).then(Mono.fromRunnable(() -> {
36                 System.out.println(1);
37             }));
38         };
39     }
40 }
复制代码

在配置文件类配置两条路由

复制代码
 1 
server.port: 7777
spring: 2 application: 3 name: gateway 4 cloud: 5 gateway: 6 discovery: 7 locator: 8 enabled: true 9 lower-case-service-id: true 10 routes: 11 - id: method_route 12 uri: http://127.0.0.1:9999 13 predicates: 14 - Method=GET 15 - id: method_route 16 uri: http://127.0.0.1:8006 17 predicates: 18 - Method=GET
复制代码

 发送请求,请求到达后匹配的是第一条路由,由此可以知道路由匹配的顺序会根据加载的顺序来

 

  4:SpringCloudGateWay从注册中心获得路由

        在官方文档中,我们可以看到有这样的一段话

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

       

复制代码
1 spring.cloud.gateway.discovery.locator.predicates[0].name: Path
2 spring.cloud.gateway.discovery.locator.predicates[0].args[pattern]: "'/'+serviceId+'/**'"
3 spring.cloud.gateway.discovery.locator.predicates[1].name: Host
4 spring.cloud.gateway.discovery.locator.predicates[1].args[pattern]: "'**.foo.com'"
5 spring.cloud.gateway.discovery.locator.filters[0].name: Hystrix
6 spring.cloud.gateway.discovery.locator.filters[0].args[name]: serviceId
7 spring.cloud.gateway.discovery.locator.filters[1].name: RewritePath
8 spring.cloud.gateway.discovery.locator.filters[1].args[regexp]: "'/' + serviceId + '/(?<remaining>.*)'"
9 spring.cloud.gateway.discovery.locator.filters[1].args[replacement]: "'/${remaining}'"
复制代码

根据文档介绍,依照这种方式,可以从注册中心获得断言与过滤器的配置

  5:SpringGateWay从数据库配置路由

      

public class DBRouteDefinitionRepository  implements RouteDefinitionRepository

 项目中实现了RouteDefinitionRepository后,springgateway会采用你实现的这个类去加载路由,如果不实现则采用他默认的方式加载路由

复制代码
 1     
 2 public class DBRouteDefinitionRepository  implements RouteDefinitionRepository {
    //保存路由
    private final Map<String, RouteDefinition> routes = synchronizedMap(new LinkedHashMap<String, RouteDefinition>());
    
    private Logger log = LoggerFactory.getLogger(DBRouteDefinitionRepository.class);
    //初始標準
    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();//从数据库中加载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();
        });
    }

}
复制代码

这个是我自己实现的类,这个类可以从数据库与配置文件中获得路由配置,从数据库中获得路由配置可以根据个人的要求来

复制代码
@Validated
public class RouteDefinition {
@NotEmpty
</span><span style="color: #0000ff;">private</span> String id =<span style="color: #000000;"> UUID.randomUUID().toString();

@NotEmpty
@Valid
</span><span style="color: #0000ff;">private</span> List&lt;PredicateDefinition&gt; predicates = <span style="color: #0000ff;">new</span> ArrayList&lt;&gt;<span style="color: #000000;">();

@Valid
</span><span style="color: #0000ff;">private</span> List&lt;FilterDefinition&gt; filters = <span style="color: #0000ff;">new</span> ArrayList&lt;&gt;<span style="color: #000000;">();

@NotNull
</span><span style="color: #0000ff;">private</span><span style="color: #000000;"> URI uri;

</span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">int</span> order = 0<span style="color: #000000;">;

</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> RouteDefinition() {
}

</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> RouteDefinition(String text) {
    </span><span style="color: #0000ff;">int</span> eqIdx = text.indexOf('='<span style="color: #000000;">);
    </span><span style="color: #0000ff;">if</span> (eqIdx &lt;= 0<span style="color: #000000;">) {
        </span><span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> ValidationException("Unable to parse RouteDefinition text '" +<span style="color: #000000;"> text
                </span>+ "'" + ", must be of the form name=value"<span style="color: #000000;">);
    }

    setId(text.substring(</span>0<span style="color: #000000;">, eqIdx));

    String[] args </span>= tokenizeToStringArray(text.substring(eqIdx + 1), ","<span style="color: #000000;">);

    setUri(URI.create(args[</span>0<span style="color: #000000;">]));

    </span><span style="color: #0000ff;">for</span> (<span style="color: #0000ff;">int</span> i = 1; i &lt; args.length; i++<span style="color: #000000;">) {
        </span><span style="color: #0000ff;">this</span>.predicates.add(<span style="color: #0000ff;">new</span><span style="color: #000000;"> PredicateDefinition(args[i]));
    }
}

</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String getId() {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> id;
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setId(String id) {
    </span><span style="color: #0000ff;">this</span>.id =<span style="color: #000000;"> id;
}

</span><span style="color: #0000ff;">public</span> List&lt;PredicateDefinition&gt;<span style="color: #000000;"> getPredicates() {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> predicates;
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> setPredicates(List&lt;PredicateDefinition&gt;<span style="color: #000000;"> predicates) {
    </span><span style="color: #0000ff;">this</span>.predicates =<span style="color: #000000;"> predicates;
}

</span><span style="color: #0000ff;">public</span> List&lt;FilterDefinition&gt;<span style="color: #000000;"> getFilters() {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> filters;
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> setFilters(List&lt;FilterDefinition&gt;<span style="color: #000000;"> filters) {
    </span><span style="color: #0000ff;">this</span>.filters =<span style="color: #000000;"> filters;
}

</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> URI getUri() {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> uri;
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setUri(URI uri) {
    </span><span style="color: #0000ff;">this</span>.uri =<span style="color: #000000;"> uri;
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> getOrder() {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> order;
}

</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> setOrder(<span style="color: #0000ff;">int</span><span style="color: #000000;"> order) {
    </span><span style="color: #0000ff;">this</span>.order =<span style="color: #000000;"> order;
}

@Override
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">boolean</span><span style="color: #000000;"> equals(Object o) {
    </span><span style="color: #0000ff;">if</span> (<span style="color: #0000ff;">this</span> ==<span style="color: #000000;"> o) {
        </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span><span style="color: #000000;">;
    }
    </span><span style="color: #0000ff;">if</span> (o == <span style="color: #0000ff;">null</span> || getClass() !=<span style="color: #000000;"> o.getClass()) {
        </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">false</span><span style="color: #000000;">;
    }
    RouteDefinition routeDefinition </span>=<span style="color: #000000;"> (RouteDefinition) o;
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> Objects.equals(id, routeDefinition.id)
            </span>&amp;&amp;<span style="color: #000000;"> Objects.equals(predicates, routeDefinition.predicates)
            </span>&amp;&amp;<span style="color: #000000;"> Objects.equals(order, routeDefinition.order)
            </span>&amp;&amp;<span style="color: #000000;"> Objects.equals(uri, routeDefinition.uri);
}

@Override
</span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span><span style="color: #000000;"> hashCode() {
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> Objects.hash(id, predicates, uri);
}

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> String toString() {
    </span><span style="color: #0000ff;">return</span> "RouteDefinition{" + "id='" + id + '\'' + ", predicates=" +<span style="color: #000000;"> predicates
            </span>+ ", filters=" + filters + ", uri=" + uri + ", order=" + order + '}'<span style="color: #000000;">;
}

}

复制代码

原文地址:https://www.cnblogs.com/saozhou/p/11320805.html

posted @ 2019-11-27 17:59  星朝  阅读(1235)  评论(0编辑  收藏  举报