当前位置:   article > 正文

Spring Cloud Gateway网关_springcloud gateway网关

springcloud gateway网关

(一)SpringCloudeGateway基本使用

Spring Cloud Gateway Spring 官方基于 Spring5.0 SpringBoot2.0 Project Reactor 等技术开发的网
旨在为微服务框架提供一种简单而有效的统一的 API 路由管理方式,统一访问接口。
Spring Cloud Gateway 作为 Spring Cloud 生态体系中的网关,目标是替代 Netflix Zuul ,其不仅提供统
一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能,例如:安全、监控 / 埋点和限流等等。
它是基于 Netty 的响应式开发模式。

 

1️⃣ 路由( route ):路由是网关最基础的部分,路由信息由一个 ID ,一个目的 URL 、一组断言工厂和一
Filter 组成。如果断言为真,则说明请求 URL 和配置的路由匹配。
2️⃣ 断言( Predicate ): Java8 中的断言函数, Spring Cloud Gateway 中的断言函数输入类型是
Spring5.0 框架中的 ServerWebExchange Spring Cloud Gateway 中的断言函数允许开发者去定义匹配
来自 http Request 中的任何信息,比如请求头和参数等。
3️⃣ 过滤器( Filter ):一个标准的 Spring WebFilter Spring Cloud Gateway 中的 Filter 分为两种类型:
Gateway Filter Global Filter 。过滤器 Filter 可以对请求和响应进行处理。

1.新建一个Gateway的模块,在pom.xml中导入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gateway</groupId>
    <artifactId>code</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gateway</name>
    <description>gateway</description>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
        <spring-boot.version>2.4.1</spring-boot.version>
        <spring-cloud.version>2020.0.0</spring-cloud.version>
        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-loadbalancer</artifactI>
</dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <mainClass>com.gateway.code.GatewayApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

 2.编写application.yml配置

server:
  #此处的8085端口号,就好像以前外置的tomcat的8080,让我们通过浏览器进行访问
  #但此服务只是做了一个路由,它会将请求路由到其它微服务(一般是消费者)进行处理
  port: 8085

spring:
  application:
    #微服务名
    name: gateway
  cloud:
    nacos:
      discovery:
        #指定nacos注册中心的地址
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          #localhost:8085/provider/user/aa
          #localhost:8085/consumer/user/aa
          #是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false
          #为true代表开启基于服务发现的路由规则。
          enabled: true
          #配置之后访问时service-id无需大写
          lower-case-service-id: true
#      routes:
#        # 路由标识(id:标识,具有唯一性)
#        - id: user-consumer-api
#          #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
#          uri: lb://consumer
#          #优先级,越小越优先
#          #order: 999
#          #路由条件(predicates:断言)
#          predicates:
#            # 路径匹配,
#            - Path=/aa/**
#          filters:
#            #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
#            #前缀过滤,请求地址:http://localhost:8084/usr/hello
#            #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
#            #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
#            - StripPrefix=1
#        # 路由标识(id:标识,具有唯一性)
#        - id: user-provider-api
#          #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
#          uri: lb://provider
#          #优先级,越小越优先
#          #order: 999
#          #路由条件(predicates:断言)
#          predicates:
#            # 路径匹配,
#            - Path=/bb/cc/**
#          filters:
#            #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
#            #前缀过滤,请求地址:http://localhost:8084/usr/hello
#            #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
#            #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
#            - StripPrefix=2
logging:
  level:
    #开启spring-Cloud-gateway的日志级别为debug,方便debug调试
    org.springframework.cloud.gateway: trace
    org.springframework.http.server.reactive: debug
    org.springframework.web.reactive: debug
    reactor.ipc.netty: debug
#springboot监控Actuator,暴露所有端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
#自定义配置
gateway:
  nacos:
    server-addr: ${spring.cloud.nacos.discovery.server-addr}
    # namespace: xxx-xx-xx-xx
    data-id: dynamic-routing.json
    group: DEFAULT_GROUP

3.使用服务名访问效果如下,访问之前先启动生成者和消费者的启动类

注:根据服务名访问

 

 4.使用路由访问

server:
  #此处的8085端口号,就好像以前外置的tomcat的8080,让我们通过浏览器进行访问
  #但此服务只是做了一个路由,它会将请求路由到其它微服务(一般是消费者)进行处理
  port: 8085

spring:
  application:
    #微服务名
    name: gateway
  cloud:
    nacos:
      discovery:
        #指定nacos注册中心的地址
        server-addr: 127.0.0.1:8848
    gateway:
      discovery:
        locator:
          #localhost:8085/provider/user/aa
          #localhost:8085/consumer/user/aa
          #是否与服务发现组件进行结合,通过service-id(必须设置成大写)转发到具体的服务实例。默认false
          #为true代表开启基于服务发现的路由规则。
          enabled: false
          #配置之后访问时service-id无需大写
          lower-case-service-id: true
      routes:
        # 路由标识(id:标识,具有唯一性)
        - id: user-consumer-api
          #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
          uri: lb://consumer
          #优先级,越小越优先
          #order: 999
          #路由条件(predicates:断言)
          predicates:
            # 路径匹配,
            #localhost:8085/user/aa 不能进
            #localhost:8085/cum/user/aa 能进
            - Path=/cum/**
          filters:
            #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
            #前缀过滤,请求地址:http://localhost:8084/usr/hello
            #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
            #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
            - StripPrefix=1
        # 路由标识(id:标识,具有唯一性)
        - id: user-provider-api
          #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
          uri: lb://provider
          #优先级,越小越优先
          #order: 999
          #路由条件(predicates:断言)
          predicates:
            # 路径匹配,
            #localhost:8085/api/prv/user/aa
            - Path=/api/prv/**
          filters:
            #路径前缀删除示例:请求/name/bar/foo,StripPrefix=2,去除掉前面两个前缀之后,最后转发到目标服务的路径为/foo
            #前缀过滤,请求地址:http://localhost:8084/usr/hello
            #此处配置去掉1个路径前缀,再配置上面的 Path=/usr/**,就将**转发到指定的微服务
            #因为这个api相当于是服务名,只是为了方便以后nginx的代码加上去的,对于服务提供者service-client来说,不需要这段地址,所以需要去掉
            - StripPrefix=2
logging:
  level:
    #开启spring-Cloud-gateway的日志级别为debug,方便debug调试
    org.springframework.cloud.gateway: trace
    org.springframework.http.server.reactive: debug
    org.springframework.web.reactive: debug
    reactor.ipc.netty: debug
#springboot监控Actuator,暴露所有端点
management:
  endpoints:
    web:
      exposure:
        include: '*'
#自定义配置
gateway:
  nacos:
    server-addr: ${spring.cloud.nacos.discovery.server-addr}
    # namespace: xxx-xx-xx-xx
    data-id: dynamic-routing.json
    group: DEFAULT_GROUP

运行效果如下:

 

 (二)动态路由设置

gateway :
nacos :
server-addr : $ { spring.cloud.nacos.discovery.server-addr }
# namespace: xxx-xx-xx-xx
data-id : dynamic-routing.json
group : DEFAULT_GROUP
配合读取类使用

1.在Nacos里面新建一隔dynamic-routing.json配置

注:点新建+号哦,我这边演示的是我已经新建好的配置

 

 

 注:配置内容如下(直接复制即可)

{

"refreshGatewayRoute": true,

"routeList": [

{

"id": "consumer-api",

"predicates": [

{

"name": "Path",

"args": {

"_genkey_0": "/cum/**"

}

}

],

"filters": [

{

"name": "StripPrefix",

"args": {

"_genkey_0": "1"

}

}

],

"uri": "lb://consumer",

"order": 0

},

{

"id": "provider-api",

"predicates": [

{

"name": "Path",

"args": {

"_genkey_0": "/api/pvr/**"

}

}

],

"filters": [

{

"name": "StripPrefix",

"args": {

"_genkey_0": "2"

}

}

],

"uri": "lb://provider",

"order": 0

}

]

}

2.在gateway模块中的pom.xml配置中导入fastjson的依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.35</version>
</dependency>

3.导入pojo实体类

作用:用来做yml注入

  1. package com.gateway.code.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import lombok.experimental.Accessors;
  6. import org.springframework.boot.context.properties.ConfigurationProperties;
  7. import org.springframework.stereotype.Component;
  8. @SuppressWarnings("all")
  9. @Data
  10. @NoArgsConstructor
  11. @AllArgsConstructor
  12. @Accessors(chain = true)
  13. @ConfigurationProperties(prefix = "gateway.nacos")
  14. @Component
  15. public class GatewayNacosProperties {
  16. private String serverAddr;
  17. private String dataId;
  18. private String namespace;
  19. private String group;
  20. }

注:下面三个实体类是用来将json格式转换成java类

(实体类中的属性对应配置内容中的json数据)

  1. package com.gateway.code.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import lombok.experimental.Accessors;
  6. import java.util.ArrayList;
  7. import java.util.List;
  8. /**
  9. * @author hgh
  10. */
  11. @SuppressWarnings("all")
  12. @Data
  13. @NoArgsConstructor
  14. @AllArgsConstructor
  15. @Accessors(chain = true)
  16. public class RouteEntity {
  17. //路由id
  18. private String id;
  19. //路由断言集合
  20. private List<PredicateEntity> predicates = new ArrayList<>();
  21. //路由过滤器集合
  22. private List<FilterEntity> filters = new ArrayList<>();
  23. //路由转发的目标uri
  24. private String uri;
  25. //路由执行的顺序
  26. private int order = 0;
  27. }
  1. package com.gateway.code.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import lombok.experimental.Accessors;
  6. import java.util.LinkedHashMap;
  7. import java.util.Map;
  8. /**
  9. * @author hgh
  10. */
  11. @SuppressWarnings("all")
  12. @Data
  13. @NoArgsConstructor
  14. @AllArgsConstructor
  15. @Accessors(chain = true)
  16. public class FilterEntity {
  17. //过滤器对应的Name
  18. private String name;
  19. //路由规则
  20. private Map<String, String> args = new LinkedHashMap<>();
  21. }
  1. package com.gateway.code.pojo;
  2. import lombok.AllArgsConstructor;
  3. import lombok.Data;
  4. import lombok.NoArgsConstructor;
  5. import lombok.experimental.Accessors;
  6. import java.util.LinkedHashMap;
  7. import java.util.Map;
  8. /**
  9. * @author hgh
  10. */
  11. @SuppressWarnings("all")
  12. @Data
  13. @NoArgsConstructor
  14. @AllArgsConstructor
  15. @Accessors(chain = true)
  16. public class PredicateEntity {
  17. //断言对应的Name
  18. private String name;
  19. //断言规则
  20. private Map<String, String> args = new LinkedHashMap<>();
  21. }

2.此实现了Spring Cloud Gateway + nacos 的动态路由

  1. package com.gateway.code;
  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.JSONObject;
  4. import com.alibaba.nacos.api.NacosFactory;
  5. import com.alibaba.nacos.api.PropertyKeyConst;
  6. import com.alibaba.nacos.api.config.ConfigService;
  7. import com.alibaba.nacos.api.config.listener.Listener;
  8. import com.alibaba.nacos.api.exception.NacosException;
  9. import com.fasterxml.jackson.databind.ObjectMapper;
  10. import com.gateway.code.pojo.FilterEntity;
  11. import com.gateway.code.pojo.GatewayNacosProperties;
  12. import com.gateway.code.pojo.PredicateEntity;
  13. import com.gateway.code.pojo.RouteEntity;
  14. import lombok.extern.slf4j.Slf4j;
  15. import org.springframework.beans.factory.annotation.Autowired;
  16. import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
  17. import org.springframework.cloud.gateway.filter.FilterDefinition;
  18. import org.springframework.cloud.gateway.handler.predicate.PredicateDefinition;
  19. import org.springframework.cloud.gateway.route.RouteDefinition;
  20. import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
  21. import org.springframework.context.ApplicationEventPublisher;
  22. import org.springframework.context.ApplicationEventPublisherAware;
  23. import org.springframework.context.annotation.Bean;
  24. import org.springframework.stereotype.Component;
  25. import org.springframework.web.util.UriComponentsBuilder;
  26. import reactor.core.publisher.Mono;
  27. import java.net.URI;
  28. import java.util.ArrayList;
  29. import java.util.List;
  30. import java.util.Properties;
  31. import java.util.concurrent.Executor;
  32. /**
  33. * 此类实现了Spring Cloud Gateway + nacos 的动态路由,
  34. * 它实现一个Spring提供的事件推送接口ApplicationEventPublisherAware
  35. */
  36. @SuppressWarnings("all")
  37. @Slf4j
  38. @Component
  39. public class DynamicRoutingConfig implements ApplicationEventPublisherAware {
  40. @Autowired
  41. private RouteDefinitionWriter routeDefinitionWriter;
  42. @Autowired
  43. private GatewayNacosProperties gatewayProperties;
  44. private ApplicationEventPublisher applicationEventPublisher;
  45. @Override
  46. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  47. this.applicationEventPublisher = applicationEventPublisher;
  48. }
  49. /**
  50. * 这个方法主要负责监听Nacos的配置变化,这里先使用参数构建一个ConfigService,
  51. * 再使用ConfigService开启一个监听,
  52. * 并且在监听的方法中刷新路由信息。
  53. */
  54. @Bean
  55. public void refreshRouting() throws NacosException {
  56. //创建Properties配置类
  57. Properties properties = new Properties();
  58. System.out.println(gatewayProperties);
  59. //设置nacos的服务器地址,从配置类GatewayProperties中获取
  60. properties.put(PropertyKeyConst.SERVER_ADDR, gatewayProperties.getServerAddr());
  61. //设置nacos的命名空间,表示从具体的命名空间中获取配置信息,不填代表默认从public获得
  62. if (gatewayProperties.getNamespace() != null) {
  63. properties.put(PropertyKeyConst.NAMESPACE, gatewayProperties.getNamespace());
  64. }
  65. //根据Properties配置创建ConfigService类
  66. ConfigService configService = NacosFactory.createConfigService(properties);
  67. //获得nacos中已有的路由配置
  68. String json = configService.getConfig(gatewayProperties.getDataId(), gatewayProperties.getGroup(), 5000);
  69. if(json == null){
  70. return;
  71. }
  72. this.parseJson(json);
  73. //添加监听器,监听nacos中的数据修改事件
  74. configService.addListener(gatewayProperties.getDataId(), gatewayProperties.getGroup(), new Listener() {
  75. @Override
  76. public Executor getExecutor() {
  77. return null;
  78. }
  79. /**
  80. * 用于接收远端nacos中数据修改后的回调方法
  81. */
  82. @Override
  83. public void receiveConfigInfo(String configInfo) {
  84. log.warn(configInfo);
  85. //获取nacos中修改的数据并进行转换
  86. parseJson(configInfo);
  87. }
  88. });
  89. }
  90. /**
  91. * 解析从nacos读取的路由配置信息(json格式)
  92. */
  93. public void parseJson(String json) {
  94. log.warn("从Nacos返回的路由配置(JSON格式):" + json);
  95. boolean refreshGatewayRoute = JSONObject.parseObject(json).getBoolean("refreshGatewayRoute");
  96. if (refreshGatewayRoute) {
  97. List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(json).getString("routeList")).toJavaList(RouteEntity.class);
  98. for (RouteEntity route : list) {
  99. update(assembleRouteDefinition(route));
  100. }
  101. } else {
  102. log.warn("路由未发生变更");
  103. }
  104. }
  105. /**
  106. * 路由更新
  107. */
  108. public void update(RouteDefinition routeDefinition) {
  109. try {
  110. this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
  111. log.warn("路由删除成功:" + routeDefinition.getId());
  112. } catch (Exception e) {
  113. log.error(e.getMessage(), e);
  114. }
  115. try {
  116. routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
  117. this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
  118. log.warn("路由更新成功:" + routeDefinition.getId());
  119. } catch (Exception e) {
  120. log.error(e.getMessage(), e);
  121. }
  122. }
  123. /**
  124. * 根据自己的路由实体类生成gateway的路由定义对象
  125. */
  126. public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {
  127. RouteDefinition definition = new RouteDefinition();
  128. // ID
  129. definition.setId(routeEntity.getId());
  130. // Predicates
  131. List<PredicateDefinition> pdList = new ArrayList<>();
  132. for (PredicateEntity predicateEntity : routeEntity.getPredicates()) {
  133. PredicateDefinition predicateDefinition = new PredicateDefinition();
  134. predicateDefinition.setArgs(predicateEntity.getArgs());
  135. predicateDefinition.setName(predicateEntity.getName());
  136. pdList.add(predicateDefinition);
  137. }
  138. definition.setPredicates(pdList);
  139. // Filters
  140. List<FilterDefinition> fdList = new ArrayList<>();
  141. for (FilterEntity filterEntity : routeEntity.getFilters()) {
  142. FilterDefinition filterDefinition = new FilterDefinition();
  143. filterDefinition.setArgs(filterEntity.getArgs());
  144. filterDefinition.setName(filterEntity.getName());
  145. fdList.add(filterDefinition);
  146. }
  147. definition.setFilters(fdList);
  148. // URI
  149. URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
  150. definition.setUri(uri);
  151. return definition;
  152. }
  153. }

运行效果如下:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/301418
推荐阅读
相关标签
  

闽ICP备14008679号