0


【SpringCloud Alibaba】Nacos Config配置管理与Gateway 网关

一、Config 远程配置

1.1 config 介绍

  1. 微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大 量的服务。 由于每个服务都需要必要的配置信息才能运行,所以一套集中式的,动态的配置管理设施是必不可少的。
  2. Spring Cloud 提供了 ConfigServer来解决这个问题,Spring Cloud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服 务应用的所有环境提供了一个中心化的外部配置。

一个使用微服务架构的应用系统可能会包括成百上千个微服务,配置各部相同,需求各不相同:

  • 不同环境不同配置:例如数据源在不同的环境(开发,测试,生产)是不同的
  • 运行期间可以动态调整。例如根据各个微服务的负载状况,动态调整数据源连接池大小或者熔断阀 值,并且调整时不停止微服务(配置修改后可以自动更新)

** 使用 Spring Cloud Alibaba Nacos Config,您可以在 Nacos Server 集中管理你 Spring Cloud 应用的外 部属性配置。 **

1.2 bootstrap.yml 配置文件

SpringBoot 默认支持propertiesYAML两种格式的配置文件。

  1. bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等
  2. application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用 的公共参数等。

bootstrap.yml 先于 application.yml 加载 !!!

1、添加依赖

  1. <!--config配置管理-->
  2. <dependency>
  3. <groupId>com.alibaba.cloud</groupId>
  4. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.cloud</groupId>
  8. <artifactId>spring-cloud-starter-bootstrap</artifactId>
  9. </dependency>

2、添加bootsrap.yml配置

  1. server:
  2. port: 8080
  3. spring:
  4. application:
  5. name: basketball
  6. cloud:
  7. nacos:
  8. server-addr: localhost:8848
  9. config:
  10. server-addr: ${spring.cloud.nacos.server-addr}
  11. #指定nacos配置中心地址
  12. prefix: ${spring.application.name}
  13. file-extension: yaml # 使用的 nacos 配置集的 dataId 的文件拓展名,同时也是Nacos 配置集的配置格式,默认为 properties
  14. group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
  15. # 共享配置集数组
  16. shared-configs:
  17. - data-id: redis.yml
  18. group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
  19. refresh: true # 是否自动刷新配置,默认为 fals
  20. - data-id: basketball.yml
  21. group: DEFAULT_GROUP # 使用的 Nacos 配置分组,默认为 DEFAULT_GROUP
  22. refresh: true # 是否自动刷新配置,默认为 false
  23. # 使用的 nacos 的命名空间(指定项目环境),
  24. namespace: 363830b6-d72e-4868-a028-6be9c2cfd267

3、对应Nacos也添加配置信息

redis.yml:

basketball.yml:

4、编写两个配置类读取Nacos配置文件属性值

5、编写测试接口类

  1. package com.example.basketball.controller;
  2. import com.example.basketball.config.EmailProperies;
  3. import com.example.basketball.config.RedisProperies;
  4. import lombok.extern.slf4j.Slf4j;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.*;
  7. import pojo.dto.IkunDto;
  8. import java.util.Map;
  9. @Slf4j
  10. @RestController
  11. @RequestMapping("/user")
  12. public class ConfigController {
  13. @Autowired
  14. private EmailProperies emailProperies;
  15. @Autowired
  16. private RedisProperies redisProperies;
  17. /*编写测试接口读取远程配置信息*/
  18. @RequestMapping("/test1")
  19. public Object test01() {
  20. return emailProperies;
  21. }
  22. @RequestMapping("/test2")
  23. public Object test02() {
  24. return redisProperies;
  25. }
  26. }

6、启动类添加刷新配置注解

7、测试

  1. 这样我们就能将一些基本配置信息添加到Nacot进行远程配置管理,**其实这里还有一个缺点:如果我们要个更换环境需要修改指定的nacos命名空间**。![](https://img-blog.csdnimg.cn/direct/30e1b3d486da4626a2436951248f0591.png)在这我们其实可以不写,把项目导成jar包,直接设置指定命名空间运行项目:

cmd指令示例:

java -jar** xxx.jar** --spring.cloud.nacos.config.namespace=xxx

二、Gateway 网关

2.1 gateway 介绍

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

1️⃣路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL、一组断言predicates)工厂和一 组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可以对请求和响应进行处理

2.2 gateway 使用

创建网关服务:

添加依赖

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-webflux</artifactId>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework.cloud</groupId>
  8. <artifactId>spring-cloud-starter-gateway</artifactId>
  9. </dependency>
  10. <!--阿里json解析-->
  11. <dependency>
  12. <groupId>com.alibaba</groupId>
  13. <artifactId>fastjson</artifactId>
  14. <version>1.2.35</version>
  15. </dependency>
  16. </dependencies>

2.2.1 方式一

本地yml配置

  1. server:
  2. port: 8082
  3. spring:
  4. application:
  5. name: gateway
  6. cloud:
  7. nacos:
  8. server-addr: localhost:8848
  9. gateway:
  10. routes:
  11. #路由标识(id:标识,具有唯一性)配合读取类使用
  12. - id: user-basketball-api
  13. #目标服务地址(uri:地址,请求转发后的地址),会自动从注册中心获得服务的IP,不需要手动写死
  14. uri: lb://ikun
  15. #优先级,越小越优先
  16. order: 999
  17. #路由条件(predicates:断言)
  18. predicates:
  19. # 路径匹配,
  20. - Path=/kun/**
  21. filters:
  22. #路径前缀删除示例
  23. - StripPrefix=1
  1. 这**样同时启动gatewayikun(消费者)服务,通过网关端口8082路径kun就能访问ikun服务的接口方法。但是这样还是不太方便,建议使用方法二动态路由远程配置**👇

2.2.2 方式二(动态路由)

**如果是跳到该目录的小帅和小美请看上面的服务创建与依赖配置哦! **

1、修改yml配置 :

  1. server:
  2. port: 8082
  3. spring:
  4. application:
  5. name: gateway
  6. cloud:
  7. nacos:
  8. server-addr: localhost:8848
  9. #自定义读取配置
  10. gateway:
  11. nacos:
  12. server-addr: ${spring.cloud.nacos.server-addr}
  13. #namespace: xxx-xx-xx-xx (指定环境命名空降如[dev,test,pro...])
  14. data-id: dynamic-routing.json
  15. group: DEFAULT_GROUP

2、添加Nacos远程配置信息

  1. {
  2. "refreshGatewayRoute": true,
  3. "routeList": [
  4. {
  5. "id": "basketball-api",
  6. "predicates": [
  7. {
  8. "name": "Path",
  9. "args": {
  10. "_genkey_0": "/ball/**"
  11. }
  12. }
  13. ],
  14. "filters": [
  15. {
  16. "name": "StripPrefix",
  17. "args": {
  18. "_genkey_0": "1"
  19. }
  20. }
  21. ],
  22. "uri": "lb://basketball",
  23. "order": 0
  24. },
  25. {
  26. "id": "ikun-api",
  27. "predicates": [
  28. {
  29. "name": "Path",
  30. "args": {
  31. "_genkey_0": "/kun/**"
  32. }
  33. }
  34. ],
  35. "filters": [
  36. {
  37. "name": "StripPrefix",
  38. "args": {
  39. "_genkey_0": "1"
  40. }
  41. }
  42. ],
  43. "uri": "lb://ikun",
  44. "order": 0
  45. }
  46. ]
  47. }

3、添加相关远程配置解析类

  1. GatewayNacosProperties:
  1. package com.example.gateway.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; //nacos服务地址
  17. private String dataId; //配置文件名称
  18. private String namespace; //指定命名空间
  19. private String group; //分组
  20. }
  1. RouteEntity
  1. package com.example.gateway.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 云村小威
  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. PredicateEntity
  1. package com.example.gateway.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 云村小威
  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. }
  1. FilterEntity
  1. package com.example.gateway.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 云村小威
  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. }

DynamicRoutingConfig : 🌟

  1. package com.example.gateway;
  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.example.gateway.pojo.FilterEntity;
  10. import com.example.gateway.pojo.GatewayNacosProperties;
  11. import com.example.gateway.pojo.PredicateEntity;
  12. import com.example.gateway.pojo.RouteEntity;
  13. import com.fasterxml.jackson.databind.ObjectMapper;
  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. @Autowired
  45. private ObjectMapper mapper;
  46. private ApplicationEventPublisher applicationEventPublisher;
  47. @Override
  48. public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
  49. this.applicationEventPublisher = applicationEventPublisher;
  50. }
  51. /**
  52. * 这个方法主要负责监听Nacos的配置变化,这里先使用参数构建一个ConfigService,
  53. * 再使用ConfigService开启一个监听,
  54. * 并且在监听的方法中刷新路由信息。
  55. */
  56. @Bean
  57. public void refreshRouting() throws NacosException {
  58. //创建Properties配置类
  59. Properties properties = new Properties();
  60. System.out.println(gatewayProperties);
  61. //设置nacos的服务器地址,从配置类GatewayProperties中获取
  62. properties.put(PropertyKeyConst.SERVER_ADDR, gatewayProperties.getServerAddr());
  63. //设置nacos的命名空间,表示从具体的命名空间中获取配置信息,不填代表默认从public获得
  64. if (gatewayProperties.getNamespace() != null) {
  65. properties.put(PropertyKeyConst.NAMESPACE, gatewayProperties.getNamespace());
  66. }
  67. //根据Properties配置创建ConfigService类
  68. ConfigService configService = NacosFactory.createConfigService(properties);
  69. //获得nacos中已有的路由配置
  70. String json = configService.getConfig(gatewayProperties.getDataId(), gatewayProperties.getGroup(), 5000);
  71. this.parseJson(json);
  72. //添加监听器,监听nacos中的数据修改事件
  73. configService.addListener(gatewayProperties.getDataId(), gatewayProperties.getGroup(), new Listener() {
  74. @Override
  75. public Executor getExecutor() {
  76. return null;
  77. }
  78. /**
  79. * 用于接收远端nacos中数据修改后的回调方法
  80. */
  81. @Override
  82. public void receiveConfigInfo(String configInfo) {
  83. log.warn(configInfo);
  84. //获取nacos中修改的数据并进行转换
  85. parseJson(configInfo);
  86. }
  87. });
  88. }
  89. /**
  90. * 解析从nacos读取的路由配置信息(json格式)
  91. */
  92. public void parseJson(String json) {
  93. log.warn("从Nacos返回的路由配置(JSON格式):" + json);
  94. boolean refreshGatewayRoute = JSONObject.parseObject(json).getBoolean("refreshGatewayRoute");
  95. if (refreshGatewayRoute) {
  96. List<RouteEntity> list = JSON.parseArray(JSONObject.parseObject(json).getString("routeList")).toJavaList(RouteEntity.class);
  97. for (RouteEntity route : list) {
  98. update(assembleRouteDefinition(route));
  99. }
  100. } else {
  101. log.warn("路由未发生变更");
  102. }
  103. }
  104. /**
  105. * 路由更新
  106. */
  107. public void update(RouteDefinition routeDefinition) {
  108. try {
  109. this.routeDefinitionWriter.delete(Mono.just(routeDefinition.getId()));
  110. log.warn("路由删除成功:" + routeDefinition.getId());
  111. } catch (Exception e) {
  112. log.error(e.getMessage(), e);
  113. }
  114. try {
  115. routeDefinitionWriter.save(Mono.just(routeDefinition)).subscribe();
  116. this.applicationEventPublisher.publishEvent(new RefreshRoutesEvent(this));
  117. log.warn("路由更新成功:" + routeDefinition.getId());
  118. } catch (Exception e) {
  119. log.error(e.getMessage(), e);
  120. }
  121. }
  122. /**
  123. * 路由定义
  124. */
  125. public RouteDefinition assembleRouteDefinition(RouteEntity routeEntity) {
  126. RouteDefinition definition = new RouteDefinition();
  127. // ID
  128. definition.setId(routeEntity.getId());
  129. // Predicates
  130. List<PredicateDefinition> pdList = new ArrayList<>();
  131. for (PredicateEntity predicateEntity : routeEntity.getPredicates()) {
  132. PredicateDefinition predicateDefinition = new PredicateDefinition();
  133. predicateDefinition.setArgs(predicateEntity.getArgs());
  134. predicateDefinition.setName(predicateEntity.getName());
  135. pdList.add(predicateDefinition);
  136. }
  137. definition.setPredicates(pdList);
  138. // Filters
  139. List<FilterDefinition> fdList = new ArrayList<>();
  140. for (FilterEntity filterEntity : routeEntity.getFilters()) {
  141. FilterDefinition filterDefinition = new FilterDefinition();
  142. filterDefinition.setArgs(filterEntity.getArgs());
  143. filterDefinition.setName(filterEntity.getName());
  144. fdList.add(filterDefinition);
  145. }
  146. definition.setFilters(fdList);
  147. // URI
  148. URI uri = UriComponentsBuilder.fromUriString(routeEntity.getUri()).build().toUri();
  149. definition.setUri(uri);
  150. return definition;
  151. }
  152. }

4、接口调用测试

** 这样就可以通过配置统一管理服务接口, 如下图所示;通过网关端口8082可访问不同服务的接口实现路由转发、处理请求和响应。**


本文转载自: https://blog.csdn.net/Justw320/article/details/135442845
版权归原作者 云村小威 所有, 如有侵权,请联系我们删除。

“【SpringCloud Alibaba】Nacos Config配置管理与Gateway 网关”的评论:

还没有评论