微服务-注册中心、配置中心、网关

image.png

组件选择

参考:官方

注册中心:SpringCloud Alibaba Nacos
配置中心:SpringCloud Alibaba Nacos
负载均衡:SpringCloud Ribbon
声明式HTTP客户端:SpringCloud Feign ——调用远程服务
负载均衡:SpringCloud Ribbon —— feign中已经整合,无需显示引用
服务容错:SpringCloud Alibaba Sentinel ——限流、降级、熔断
API网关:SpringCloud Gateway ——webflux 编程模式
调用链路监控:SpringCloud Sleuth
分布式事务:SpringCloud Alibaba Seata ——原Fescar

下载 Nacos Server

下载地址:Github Release 由上面版本选择可知:当前对应 Nacos 版本为1.2.1

下载对应系统的tar包(Linux)或者zip包(Windows),解压后运行bin目录下的可执行文件即可运行Nacos

引入Nacos作为注册中心

1. pom文件引入依赖

  • common模块 ```xml <?xml version=”1.0” encoding=”UTF-8”?> <project xmlns=”http://maven.apache.org/POM/4.0.0

    1. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    2. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    1. <artifactId>mall</artifactId>
    2. <groupId>groupId</groupId>
    3. <version>1.0-SNAPSHOT</version>

    4.0.0

    mall-common

    每一个微服务公共的依赖,bean,工具类等

    1. <!-- mybatis-plus-->
    2. <dependency>
    3. <groupId>com.baomidou</groupId>
    4. <artifactId>mybatis-plus-boot-starter</artifactId>
    5. <version>3.2.0</version>
    6. </dependency>
    7. <dependency>
    8. <groupId>org.projectlombok</groupId>
    9. <artifactId>lombok</artifactId>
    10. <version>1.18.8</version>
    11. </dependency>
    12. <!-- https://mvnrepository.com/artifact/org.apache.httpcomponents/httpcore -->
    13. <dependency>
    14. <groupId>org.apache.httpcomponents</groupId>
    15. <artifactId>httpcore</artifactId>
    16. <version>4.4.12</version>
    17. </dependency>
  1. <dependency>
  2. <groupId>commons-lang</groupId>
  3. <artifactId>commons-lang</artifactId>
  4. <version>2.6</version>
  5. </dependency>
  6. <!-- 导入mysql驱动 -->
  7. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>8.0.17</version>
  12. </dependency>
  13. <dependency>
  14. <groupId>javax.servlet</groupId>
  15. <artifactId>servlet-api</artifactId>
  16. <version>2.5</version>
  17. <scope>provided</scope>
  18. </dependency>
  19. <!-- 服务注册/发现-->
  20. <dependency>
  21. <groupId>com.alibaba.cloud</groupId>
  22. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>javax.validation</groupId>
  26. <artifactId>validation-api</artifactId>
  27. <version>2.0.1.Final</version>
  28. </dependency>
  29. <dependency>
  30. <groupId>org.slf4j</groupId>
  31. <artifactId>slf4j-api</artifactId>
  32. <version>1.7.32</version>
  33. </dependency>
  34. <dependency>
  35. <groupId>org.springframework.boot</groupId>
  36. <artifactId>spring-boot-test</artifactId>
  37. <version>2.1.8.RELEASE</version>
  38. <scope>test</scope>
  39. </dependency>
  40. <dependency>
  41. <groupId>junit</groupId>
  42. <artifactId>junit</artifactId>
  43. <version>4.13.2</version>
  44. <scope>test</scope>
  45. </dependency>
  46. <dependency>
  47. <groupId>org.junit.jupiter</groupId>
  48. <artifactId>junit-jupiter-api</artifactId>
  49. <version>5.8.0-M1</version>
  50. <scope>test</scope>
  51. </dependency>
  52. <!-- 配置中心来做配置管理-->
  53. <dependency>
  54. <groupId>com.alibaba.cloud</groupId>
  55. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  56. </dependency>
  57. </dependencies>
  58. <dependencyManagement>
  59. <dependencies>
  60. <dependency>
  61. <groupId>com.alibaba.cloud</groupId>
  62. <artifactId>spring-cloud-alibaba-dependencies</artifactId>
  63. <version>2.1.0.RELEASE</version>
  64. <type>pom</type>
  65. <scope>import</scope>
  66. </dependency>
  67. </dependencies>
  68. </dependencyManagement>

  1. - coupon模块
  2. ```xml
  3. <?xml version="1.0" encoding="UTF-8"?>
  4. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  5. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  6. <modelVersion>4.0.0</modelVersion>
  7. <parent>
  8. <groupId>org.springframework.boot</groupId>
  9. <artifactId>spring-boot-starter-parent</artifactId>
  10. <version>2.1.8.RELEASE</version>
  11. <relativePath/> <!-- lookup parent from repository -->
  12. </parent>
  13. <groupId>com.ht.mall</groupId>
  14. <artifactId>gulimall-coupon</artifactId>
  15. <version>0.0.1-SNAPSHOT</version>
  16. <name>mall-coupon</name>
  17. <description>商城-优惠卷服务</description>
  18. <properties>
  19. <java.version>1.8</java.version>
  20. <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
  21. </properties>
  22. <dependencies>
  23. <dependency>
  24. <groupId>groupId</groupId>
  25. <artifactId>mall-common</artifactId>
  26. <version>1.0-SNAPSHOT</version>
  27. </dependency>
  28. <dependency>
  29. <groupId>org.springframework.boot</groupId>
  30. <artifactId>spring-boot-starter-web</artifactId>
  31. </dependency>
  32. <dependency>
  33. <groupId>org.springframework.cloud</groupId>
  34. <artifactId>spring-cloud-starter-openfeign</artifactId>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-test</artifactId>
  39. <scope>test</scope>
  40. </dependency>
  41. <dependency>
  42. <groupId>org.junit.jupiter</groupId>
  43. <artifactId>junit-jupiter-api</artifactId>
  44. <version>5.8.0-M1</version>
  45. <scope>test</scope>
  46. </dependency>
  47. </dependencies>
  48. <dependencyManagement>
  49. <dependencies>
  50. <dependency>
  51. <groupId>org.springframework.cloud</groupId>
  52. <artifactId>spring-cloud-dependencies</artifactId>
  53. <version>${spring-cloud.version}</version>
  54. <type>pom</type>
  55. <scope>import</scope>
  56. </dependency>
  57. </dependencies>
  58. </dependencyManagement>
  59. <build>
  60. <plugins>
  61. <plugin>
  62. <groupId>org.springframework.boot</groupId>
  63. <artifactId>spring-boot-maven-plugin</artifactId>
  64. </plugin>
  65. </plugins>
  66. </build>
  67. </project>

2. yaml文件增加配置

在 coupon 中的application.yml 配置文件中配置 Nacos Server 地址和微服务名称

  1. spring:
  2. application:
  3. name: mall-coupon
  4. datasource:
  5. driver-class-name: com.mysql.cj.jdbc.Driver
  6. url: jdbc:mysql://192.168.1.103:3306/mall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
  7. username: root
  8. password: root
  9. cloud:
  10. nacos:
  11. discovery:
  12. server-addr: localhost:8848
  13. mybatis-plus:
  14. mapper-locations: classpath:/mapper/**/*.xml
  15. global-config:
  16. db-config:
  17. id-type: auto
  18. server:
  19. port: 7000

3. 主启动类增加注解

使用 @EnableDiscoveryClient 注解开启服务注册与发现功能

  1. @MapperScan("com.ht.mall.product.dao")
  2. @SpringBootApplication
  3. @EnableDiscoveryClient
  4. public class MallCouponApplication {
  5. public static void main(String[] args) {
  6. SpringApplication.run(MallCouponApplication.class, args);
  7. }
  8. }

此时,启动Nacos,运行主启动类启动服务后,在浏览器打开配置文件中的地址:localhost:8848/nacos (账号密码:nacos/nacos)中就可以看到当前服务已经注册到 Nacos 服务列表中

其他服务以同样方式配置即可

引入Feign远程服务调用

测试member和coupon的远程调用

想要获取当前会员领取到的所有优惠券。先去注册中心找优惠券服务, 注册中心调一台优惠券服务器给会员,会员服务器发送请求给这台优 惠券服务器,然后对方响应。

Feign与注册中心
spring cloud feign

声明式远程调用

feign是一个声明式的HTTP客户端,他的目的就是让远程调用更加简单。
给远程服务发的是HTTP请求。

  1. 会员服务想要远程调用优惠券服务,只需要给会员服务里引入openfeign依赖,他就有了远程调用其他服务的能力。

    1. <dependency>
    2. <groupId>org.springframework.cloud</groupId>
    3. <artifactId>spring-cloud-starter-openfeign</artifactId>
    4. </dependency>
  2. 在coupon中修改如下的内容

    1. @RequestMapping("coupon/coupon")
    2. public class CouponController {
    3. @Autowired
    4. private CouponService couponService;
    5. @RequestMapping("/member/list")
    6. public R membercoupons(){ //全系统的所有返回都返回R
    7. // 应该去数据库查用户对于的优惠券,但这个我们简化了,不去数据库查了,构造了一个优惠券给他返回
    8. CouponEntity couponEntity = new CouponEntity();
    9. couponEntity.setCouponName("满100减10");//优惠券的名字
    10. return R.ok().put("coupons",Arrays.asList(couponEntity));
    11. }
  3. 这样我们准备好了优惠券的调用内容 在member的配置类上加注解@EnableFeignClients(basePackages=”com.ht.mall.member.feign”), 告诉spring这里面是一个远程调用客户端,member要调用的接口

    1. @SpringBootApplication
    2. @EnableDiscoveryClient
    3. @EnableFeignClients(basePackages="com.ht.mall.member.feign")
    4. public class MallMemberApplication {
    5. public static void main(String[] args) {
    6. SpringApplication.run(MallMemberApplication .class, args);
    7. }
    8. }
  4. 调用刚才写的优惠券的功能

复制函数部分,在member的com.ht.mall.member.feign包下新建接口:

  1. /**
  2. * 告诉spring cloud这个接口是一个远程客户端
  3. */
  4. @FeignClient("mall-coupon")
  5. public interface CouponFeignService {
  6. /**
  7. * 调用coupon服务,再去调用coupon服务/coupon/coupon/member/list对应的方法
  8. * @return 得到一个R对象
  9. */
  10. @RequestMapping("/coupon/coupon/member/list")
  11. public R memberCoupons();
  12. }
  1. 然后我们在member的控制层写一个测试请求

    1. @RestController
    2. @RequestMapping("member/member")
    3. public class MemberController {
    4. @Autowired
    5. private MemberService memberService;
    6. @Autowired
    7. CouponFeignService couponFeignService;
    8. @RequestMapping("/coupons")
    9. public R test() {
    10. MemberEntity memberEntity = new MemberEntity();
    11. memberEntity.setNickname("张三");
    12. // 假设张三去数据库查了后返回了张三的优惠券信息
    13. R memberCoupons = couponFeignService.memberCoupons();
    14. // 打印会员和优惠券信息
    15. return R.ok().put("member", memberEntity).put("coupons", memberCoupons.get("coupons"));
    16. }
    17. ......
    18. }
  2. 重新启动服务

http://localhost:8000/member/member/coupons

  1. {"msg":"success","code":0,"coupons":[{"id":null,"couponType":null,"couponImg":null,"couponName":"满100减10","num":null,"amount":null,"perLimit":null,"minPoint":null,"startTime":null,"endTime":null,"useType":null,"note":null,"publishCount":null,"useCount":null,"receiveCount":null,"enableStartTime":null,"enableEndTime":null,"code":null,"memberLevel":null,"publish":null}],"member":{"id":null,"levelId":null,"username":null,"password":null,"nickname":"张三","mobile":null,"email":null,"header":null,"gender":null,"birth":null,"city":null,"job":null,"sign":null,"sourceType":null,"integration":null,"growth":null,"status":null,"createTime":null}}

引入Nacos作为配置中心

参考:官方介绍

1. common模块引入nacos-config依赖

  1. <dependency>
  2. <groupId>com.alibaba.cloud</groupId>
  3. <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
  4. </dependency>

2. 配置 Nacos Config 元数据

在服务模块新建bootstrap.properties
此处以coupon服务为例:

  1. spring.application.name=mall-coupon
  2. spring.cloud.nacos.config.server-addr=localhost:8848

3. 测试读取配置中心配置

给配置中心新增一个配置
image.png
读取配置
application.properties

  1. coupon.user.name=zhangsan2
  2. coupon.user.age=20

CouponController.java
@RefreseScope:动态刷新,修改配置中心配置不需要重新启动项目

  1. @RefreshScope
  2. @RestController
  3. @RequestMapping("coupon/coupon")
  4. public class CouponController {
  5. @Autowired
  6. private CouponService couponService;
  7. @Value("${coupon.user.name}")
  8. private String name;
  9. @Value("${coupon.user.age}")
  10. private Integer age;
  11. @RequestMapping("/test")
  12. public R test() {
  13. return R.ok().put("name", name).put("age", age);
  14. }
  15. }

请求 /coupon/coupon/test 可以看到配置中心的数据,修改配置中心的配置,刷新可自动更新,nacos的配置内容优先于项目本地的配置内容。

4. Nacos 命名空间

为了对不同服务之间进行配置隔离,这里为每个微服务创建自己的命名空间。
image.png
后端代码中在 bootstrap.properties 配置属于自己服务的命名空间

  1. spring.application.name=mall-coupon
  2. spring.cloud.nacos.config.server-addr=localhost:8848
  3. spring.cloud.nacos.config.namespace=eed1d158-6019-487f-b38a-cf79430eba44

5. 加载多配置集

  • 配置集:一组相关或不相关配置项的集合。
  • 配置集ID:类似于配置文件名,即Data ID
  • 配置分组:默认所有的配置集都属于DEFAULT_GROUP。自己可以创建分组,比如双十一,618,双十二

spring.cloud.nacos.config.group=DEFAULT_GROUP # 更改配置分组
最终方案:每个微服务创建自己的命名空间,然后使用配置分组区分环境(dev/test/prod)


把原来application.yml里的内容都分文件抽离出去,在nacos里创建好后,指定coupons要导入的配置即可。
image.png

  • datasource.yml

    1. spring:
    2. datasource:
    3. driver-class-name: com.mysql.cj.jdbc.Driver
    4. url: jdbc:mysql://192.168.1.103:3306/mall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    5. username: root
    6. password: root
  • mybatis.yml

    1. mybatis-plus:
    2. mapper-locations: classpath:/mapper/**/*.xml
    3. global-config:
    4. db-config:
    5. id-type: auto
  • other.yml ```yaml spring: application: name: mall-coupon cloud: nacos:

    1. discovery:
    2. server-addr: localhost:8848

server: port: 7000

  1. 注释application.yml的内容<br />修改coupon里的bootstrap.properties
  2. ```yaml
  3. # 改名字,对应nacos里的配置文件名
  4. spring.application.name=mall-coupon
  5. spring.cloud.nacos.config.server-addr=localhost:8848
  6. # 可以选择对应的命名空间 ,即写上对应环境的命名空间ID
  7. spring.cloud.nacos.config.namespace=eed1d158-6019-487f-b38a-cf79430eba44
  8. # 配置文件所在的组
  9. spring.cloud.nacos.config.group=dev
  10. # 加载多配置集
  11. spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
  12. spring.cloud.nacos.config.ext-config[0].group=dev
  13. spring.cloud.nacos.config.ext-config[0].refresh=true
  14. spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
  15. spring.cloud.nacos.config.ext-config[1].group=dev
  16. spring.cloud.nacos.config.ext-config[1].refresh=true
  17. spring.cloud.nacos.config.ext-config[2].data-id=other.yml
  18. spring.cloud.nacos.config.ext-config[2].group=dev
  19. spring.cloud.nacos.config.ext-config[2].refresh=true

引入Gateway作为API网关

参考:官网

创建网关子模块mall-gateway

pom.xml

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <parent>
  6. <groupId>org.springframework.boot</groupId>
  7. <artifactId>spring-boot-starter-parent</artifactId>
  8. <version>2.1.8.RELEASE</version>
  9. <relativePath/> <!-- lookup parent from repository -->
  10. </parent>
  11. <groupId>com.ht.mall</groupId>
  12. <artifactId>mall-gateway</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>mall-gateway</name>
  15. <description>API网关</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
  19. </properties>
  20. <dependencies>
  21. <dependency>
  22. <groupId>groupId</groupId>
  23. <artifactId>mall-common</artifactId>
  24. <version>1.0-SNAPSHOT</version>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.springframework.cloud</groupId>
  28. <artifactId>spring-cloud-starter-gateway</artifactId>
  29. <version>2.1.0.RELEASE</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.springframework.boot</groupId>
  33. <artifactId>spring-boot-starter</artifactId>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-starter-test</artifactId>
  38. <scope>test</scope>
  39. </dependency>
  40. </dependencies>
  41. <build>
  42. <plugins>
  43. <plugin>
  44. <groupId>org.springframework.boot</groupId>
  45. <artifactId>spring-boot-maven-plugin</artifactId>
  46. </plugin>
  47. </plugins>
  48. </build>
  49. </project>

主启动类

  1. @EnableDiscoveryClient
  2. @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
  3. public class MallGatewayApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(MallGatewayApplication.class, args);
  6. }
  7. }

配置nacos注册中心地址applicaion.properties

  1. spring.application.name=mall-gateway
  2. spring.cloud.nacos.discovery.server-addr=localhost:8848
  3. server.port=88

bootstrap.properties 填写配置中心地址

  1. spring.application.name=mall-gateway
  2. spring.cloud.nacos.config.server-addr=localhost:8848
  3. spring.cloud.nacos.config.namespace=cfc9231c-e4d3-4f2e-ad7a-c12faffbf7dc

在gateway命名空间里创建文件mall-gateway.yml

  1. spring:
  2. application:
  3. name: mall-gateway

在项目里创建application.yml

  1. spring:
  2. cloud:
  3. gateway:
  4. routes:
  5. #Query A 参数有A就行,Query B,C 参数B的值为C即可
  6. #实现针对于“http://localhost:88/hello?url=baidu”,转发到“https://www.baidu.com/hello”,
  7. #针对于“http://localhost:88/hello?url=qq”的请求,转发到“https://www.qq.com/hello”
  8. - id: baidu_route
  9. uri: http://www.baidu.com
  10. predicates:
  11. - Query=url,baidu
  12. - id: test_route
  13. uri: http://www.qq.com
  14. predicates:
  15. - Query=url,qq

测试:

启动项目分别请求:
localhost:88?url=baidu
localhost:88?url=qq
会分别跳转到百度和github 表示成功。