最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服务环境搭建
作者:mmseoamin日期:2023-12-25

最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba 专栏

2、服务治理 Nacos Discovery

3、远程调用负载均衡 Ribbon

4、远程调用Feign

5、服务熔断降级 Sentinel

源码

1 一些说明

为了方便讲解SpringCloud课程,我们以最常见的电商项目2个核心模块:商品模块、订单模块为例子,一一讲解SpringCloud组件的使用。

学习SpringCloud组件要诀:

1>能解决啥问题

2>怎么解决(理解原理)

3>API调用(代码怎么写)–建议写3遍–【1遍抄全,2遍思考,3遍掌握】

4>总结,开口表述

5>类比以前代码结构

微服务-----完整项目按功能分类拆分成n个子项目/子模块,这些子模块能对外提供对应的功能。我们称这些服务为微服务

落地到代码:单看子项目,每个子项目就是一个完整项目(springmvc项目)----记住没啥高大上的

商品微服务

  • 对外提供查询商品列表接口
  • 对外提供查询某个商品信息接口

    订单微服务

    • 对外提供创建订单接口

      服务调用

      在微服务架构中,最常见的场景就是微服务之间的相互调用。以下单为例子:客户向订单微服务发起一个下单的请求,在进行保存订单之前需要调用商品微服务查询商品的信息。

      最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服务环境搭建,在这里插入图片描述,第1张

      一般把调用方称为服务消费者,把被调用方称为服务提供者。

      上例中,订单微服务就是服务消费者, 而商品微服务是服务提供者。

      2 技术选型

      JDK17

      持久层: MyBatis-Plus

      数据库: MySQL5.7

      其他: SpringCloud Alibaba 技术栈

      服务注册与发现:Nacos 
      分布式事务:Seata
      网关:Spring Cloud Gateway
      服务调用:OpenFeign
      鉴权:Spring Authorization Server 、Oauth2.1
      消息队列:rocketmq
      限流、熔断:sentinel
      链路追踪:Micrometer Tracing
      接口文档:knife4j
      

      3 模块设计

      — shop-parent 父工程

      ​ — shop-product-api 商品微服务api 【存放商品实体】

      ​ — shop-product-server 商品微服务 【端口:808x】

      ​ — shop-order-api 订单微服务api 【存放订单实体】

      ​ — shop-order-server 订单微服务 【端口:809x】

      最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服务环境搭建,在这里插入图片描述,第2张

      shop-product-server:子项目-商品微服务,对外提供查询商品信息的接口

      shop-order-server:子项目-订单微服务,对外提供创建订单的接口

      shop-product-api / shop-order-api : 各自微服务依赖的实体类,为啥要拆开?答案是:解耦

      4 版本说明

      ​ https://github.com/alibaba/spring-cloud-alibaba/wiki/版本说明

      最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服务环境搭建,在这里插入图片描述,第3张

      5 创建父工程

      创建 shop-parent 一个maven工程,然后在pom.xml文件中添加下面内容

      
      
          4.0.0
          
              org.springframework.boot
              spring-boot-starter-parent
              3.0.2
               
          
          com.example
          shop
          1.0.0
          shop-parent
          pom
          
              shop-product-api
              shop-product-server
          
          
              17
              UTF-8
              UTF-8
              2022.0.0
              2022.0.0.0-RC2
          
          
              
                  
                      org.springframework.cloud
                      spring-cloud-dependencies
                      ${spring-cloud.version}
                      pom
                      import
                  
                  
                      com.alibaba.cloud
                      spring-cloud-alibaba-dependencies
                      ${spring-cloud-alibaba.version}
                      pom
                      import
                  
              
          
      
      

      6 创建商品微服务

      6.1 创建shop-product-api项目,然后在pom.xml文件中添加下面内容

      
      
          4.0.0
          
              com.example
              shop
              1.0.0
          
          shop-product-api
          1.0.0
          jar
          
              17
          
          
              
                  com.baomidou
                  mybatis-plus-boot-starter
                  3.5.3.1
              
              
                  org.projectlombok
                  lombok
              
          
      
      

      6.2 创建实体类

      package com.example.domain;
      import com.baomidou.mybatisplus.annotation.IdType;
      import com.baomidou.mybatisplus.annotation.TableId;
      import com.baomidou.mybatisplus.annotation.TableName;
      import lombok.Getter;
      import lombok.Setter;
      import lombok.ToString;
      import java.io.Serializable;
      //商品
      @Getter
      @Setter
      @ToString
      @TableName("t_product")
      public class Product implements Serializable {
          //主键
          @TableId(type= IdType.AUTO)
          private Long id;
          //商品名称
          private String name;
          //商品价格
          private Double price;
          //库存
          private Integer stock;
      }
      

      6.3 创建shop-product-server项目,然后在pom.xml文件中添加下面内容

      
      
          4.0.0
          
              com.example
              shop
              1.0.0
          
          shop-product-server
          1.0.0
          
              17
          
          
              
                  org.springframework.boot
                  spring-boot-starter-web
              
              
                  org.springframework.boot
                  spring-boot-starter-test
                  test
              
              
                  mysql
                  mysql-connector-java
              
              
                  com.alibaba
                  fastjson
                  2.0.32
              
              
                  com.example
                  shop-product-api
                  1.0.0
              
          
          
              
                  
                      org.springframework.boot
                      spring-boot-maven-plugin
                  
              
          
      
      

      6.4 编写配置文件application.yml

      server:
        port: 8081
      spring:
        application:
          name: product-service
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/shop-product?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
          username: root
          password: aaaaaa
      

      6.5 在数据库中创建shop-product的数据库

      CREATE TABLE `t_product` (
        `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
        `name` varchar(255) DEFAULT NULL COMMENT '商品名称',
        `price` double(10,2) DEFAULT NULL COMMENT '商品价格',
        `stock` int DEFAULT NULL COMMENT '库存',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
      
      INSERT INTO t_product VALUE(NULL,'小米','1000','5000'); 
      INSERT INTO t_product VALUE(NULL,'华为','2000','5000'); 
      INSERT INTO t_product VALUE(NULL,'苹果','3000','5000'); 
      INSERT INTO t_product VALUE(NULL,'OPPO','4000','5000');
      

      6.6 创建ProductMapper

      package com.example.server.mapper;
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.example.domain.Product;
      public interface ProductMapper extends BaseMapper {
      }
      

      6.7 创建ProductService接口和实现类

      package com.example.server.service;
      import com.baomidou.mybatisplus.extension.service.IService;
      import com.example.domain.Product;
      public interface ProductService extends IService {
      }
      
      package com.example.server.service.impl;
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.example.domain.Product;
      import com.example.server.mapper.ProductMapper;
      import com.example.server.service.ProductService;
      import org.springframework.stereotype.Service;
      import org.springframework.transaction.annotation.Transactional;
      @Service
      @Transactional
      public class ProductServiceImpl extends ServiceImpl implements ProductService {
      }
      

      6.8 创建Controller

      package com.example.server.controller;
      import com.alibaba.fastjson2.JSON;
      import com.example.domain.Product;
      import com.example.server.service.ProductService;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      @RestController
      @Slf4j
      public class ProductController {
          @Autowired
          private ProductService productService;
          //商品信息查询
          @RequestMapping("/products/{pid}")
          public Product findByPid(@PathVariable("pid") Long pid) {
              log.info("接下来要进行{}号商品信息的查询", pid);
              Product product = productService.getById(pid);
              log.info("商品信息查询成功,内容为{}", JSON.toJSONString(product));
              return product;
          }
      }
      

      6.9 编写启动类ProductServer.java

      package com.example.server;
      import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      @SpringBootApplication
      @MapperScan("com.example.server.mapper")
      public class ShopProductServerApplication {
          public static void main(String[] args) {
              SpringApplication.run(ShopProductServerApplication.class, args);
          }
      }
      

      6.10 通过浏览器访问服务

      最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服务环境搭建,在这里插入图片描述,第4张

      7 创建订单微服务

      7.1 创建shop-order-api项目,然后在pom.xml文件中添加下面内容

      
      
          4.0.0
          
              com.example
              shop
              1.0.0
          
          shop-order-api
          1.0.0
          
              17
          
          
              
                  com.baomidou
                  mybatis-plus-boot-starter
                  3.5.3.1
              
              
                  org.projectlombok
                  lombok
              
          
      
      

      7.2 创建实体类

      package com.example.domain;
      import com.baomidou.mybatisplus.annotation.IdType;
      import com.baomidou.mybatisplus.annotation.TableId;
      import com.baomidou.mybatisplus.annotation.TableName;
      import lombok.Getter;
      import lombok.Setter;
      import lombok.ToString;
      import java.io.Serializable;
      //订单
      @Getter
      @Setter
      @ToString
      @TableName("t_order")
      public class Order implements Serializable {
          //订单id
          @TableId(type = IdType.AUTO)
          private Long id;
          //用户id
          private Long uid;
          //用户名
          private String username;
          //商品id
          private Long pid;
          //商品名称
          private String productName;
          //商品单价
          private Double productPrice;
          //购买数量
          private Integer number;
      }
      

      7.3 创建shop-order-server项目,然后在pom.xml文件中添加下面内容

      
      
          4.0.0
          
              com.example
              shop
              1.0.0
          
          shop-order-server
          1.0.0
          
              17
          
          
              
                  org.springframework.boot
                  spring-boot-starter-web
              
              
                  org.springframework.boot
                  spring-boot-starter-test
                  test
              
              
                  mysql
                  mysql-connector-java
              
              
                  com.alibaba
                  fastjson
                  2.0.32
              
              
                  com.example
                  shop-order-api
                  1.0.0
              
          
          
              
                  
                      org.springframework.boot
                      spring-boot-maven-plugin
                  
              
          
      
      

      7.4 编写配置文件application.yml

      server:
        port: 8091
      spring:
        application:
          name: order-service
        datasource:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://localhost:3306/shop-order?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
          username: root
          password: aaaaaa
      

      7.5 在数据库中创建shop-order的数据库

      CREATE TABLE `t_order` (
        `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
        `uid` bigint DEFAULT NULL COMMENT '用户id',
        `username` varchar(255) DEFAULT NULL COMMENT '用户名称',
        `pid` bigint DEFAULT NULL COMMENT '商品id',
        `product_name` varchar(255) DEFAULT NULL COMMENT '商品名称',
        `product_price` double(255,0) DEFAULT NULL COMMENT '商品单价',
        `number` int DEFAULT NULL COMMENT '购买数量',
        PRIMARY KEY (`id`)
      ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;
      

      7.6 创建OrderMapper

      package com.example.server.mapper;
      import com.baomidou.mybatisplus.core.mapper.BaseMapper;
      import com.example.domain.Order;
      public interface OrderMapper extends BaseMapper {
      }
      

      7.7 创建OrderService接口和实现类

      package com.example.server.service;
      import com.baomidou.mybatisplus.extension.service.IService;
      import com.example.domain.Order;
      public interface OrderService extends IService {
          Order createOrder(Long pid, Long uid);
      }
      
      package com.example.server.service.impl;
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.example.domain.Order;
      import com.example.server.mapper.OrderMapper;
      import com.example.server.service.OrderService;
      import org.springframework.stereotype.Service;
      @Service
      public class OrderServiceImpl extends ServiceImpl implements OrderService {
          @Override
          public Order createOrder(Long pid, Long uid) {
              return null;
          }
      }
      

      7.8 创建Controller

      package com.example.server.controller;
      import com.example.domain.Order;
      import com.example.server.service.OrderService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      @RestController
      @RequestMapping("orders")
      public class OrderController {
          @Autowired
          private OrderService orderService;
          @PostMapping("/save")  
          public Order order(Long pid, Long uid){
              return orderService.createOrder(pid, uid);
          }
      }
      

      7.9 编写启动类OrderServer.java

      package com.example.server;
      import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      @SpringBootApplication
      @MapperScan("com.example.server.mapper")
      public class ShopOrderServerApplication {
          public static void main(String[] args) {
              SpringApplication.run(ShopOrderServerApplication.class, args);
          }
      }
      

      8 服务间如何进行远程调用

      现在存在一个问题,order-server服务创建订单操作需要配置商品信息,此时怎么办?

      @Service
      public class OrderServiceImpl extends ServiceImpl implements IOrderService {
          @Override
          public Order createOrder(Long pid, Long uid) {
              Order order = new Order();
              //商品??
              Product product = null;
              order.setPid(pid);
              order.setProductName(product.getName());
              order.setProductPrice(product.getPrice());
              //用户
              order.setUid(1L);
              order.setUsername("dafei");
              order.setNumber(1);
              super.save(order);
              return order;
          }
      }
      

      思考,谁能提供商品信息查询逻辑呢?

      答案:product-server,.

      问题来了,怎么调用?这里引入一个新问题:服务与服务间如何调用(交互)?

      最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服务环境搭建,在这里插入图片描述,第5张

      问题来了,怎么用java代码调用发起http接口调用嗯?

      答案是:RestTemplate

      RestTempate 是SpringMVC提供专门用于访问http请求的工具类

      8.1 在shop-order-server项目启动类上添加RestTemplate的bean配置

      package com.example.server;
      import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.boot.SpringApplication;
      import org.springframework.boot.autoconfigure.SpringBootApplication;
      import org.springframework.context.annotation.Bean;
      import org.springframework.web.client.RestTemplate;
      @SpringBootApplication
      @MapperScan("com.example.server.mapper")
      public class ShopOrderServerApplication {
          public static void main(String[] args) {
              SpringApplication.run(ShopOrderServerApplication.class, args);
          }
          @Bean
          public RestTemplate restTemplate(){
              return new RestTemplate();
          }
      }
      

      8.2 在OrderServiceImpl中注入RestTemplate并实现远程调用

      package com.example.server.service.impl;
      import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
      import com.example.domain.Order;
      import com.example.domain.Product;
      import com.example.server.mapper.OrderMapper;
      import com.example.server.service.OrderService;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.stereotype.Service;
      import org.springframework.web.client.RestTemplate;
      @Service
      public class OrderServiceImpl extends ServiceImpl implements OrderService {
          @Autowired
          private RestTemplate restTemplate;
          @Override
          public Order createOrder(Long pid, Long uid) {
              Order order = new Order();
              //商品
              //方案1:通过restTemplate方式
              String url  = "http://localhost:8081/products/" + pid;
              Product product = restTemplate.getForObject(url, Product.class);
              order.setPid(pid);
              order.setProductName(product.getName());
              order.setProductPrice(product.getPrice());
              //用户
              order.setUid(uid);
              order.setUsername("张三");
              order.setNumber(1);
              System.out.println(order);
              super.save(order);
              return order;
          }
      }
      

      最新版 !快速掌握JDK17 + springboot3 + springcloud Alibaba : 1、 微服务环境搭建,在这里插入图片描述,第6张

      上面操作确实完成的服务间调用问题,但是代码很不优雅,存在着一定小瑕疵,比如:ip,端口变了呢?

      • 一旦服务提供者(商品服务)地址变化,就需要手工修改代码

      • 一旦是多个服务(商品服务)提供者,无法实现负载均衡功能

      • 一旦服务变得越来越多,人工维护调用关系困难

        那怎么办呢, 这时候得引入SpringCloud Alibaba第一个组件:

        **组件:**注册中心–Nacos

        功能:动态的实现服务治理。