• 手把手教你10分钟入门微服务开发


    大体了解微服务概念之后,接下里使用一个简单案例,让你10分钟入门微服务开发。

    开始前的说明

    1>简单说明

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

    学习SpringCloud组件要诀:不求甚解

    1>能解决啥问题

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

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

    4>总结,开口表述

    5>类比传统的代码结构

    2>服务拆分

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

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

    商品微服务

    • 对外提供查询商品列表接口

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

    订单微服务

    • 对外提供创建订单接口

    3>服务提供者与调用者

    以下单为例子:客户向订单微服务发起一个下单的请求,在进行保存订单之前需要调用商品微服务查询商品的信息。

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

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

    技术选型

    持久层: MyBatis-Plus

    数据库: MySQL5.7

    其他: SpringCloud Alibaba 技术栈,SpringCloud Hoxton.SR8

    注意:往下学习前,希望你有mysql,mybatis,maven,java基础,原因:接下来的学习要用到

    项目结构模块

    需求:使用微服务方式实现用户下单

    分析:根据微服务规则,拆分成商品服务,订单服务。

    --- shop-parent 父工程

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

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

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

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

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

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

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

    构建微服务项目

    创建父工程

    创建shop-parent一个maven工程,目的用于管理项目最核心的依赖

    1>创建maven项目shop-parent

     2>在项目pom.xml文件中导入下面的依赖

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <modelVersion>4.0.0modelVersion>
    6. <groupId>com.langfeiyesgroupId>
    7. <artifactId>shop-parentartifactId>
    8. <version>1.0.0version>
    9. <packaging>pompackaging>
    10. <parent>
    11. <groupId>org.springframework.bootgroupId>
    12. <artifactId>spring-boot-starter-parentartifactId>
    13. <version>2.3.2.RELEASEversion>
    14. parent>
    15. <properties>
    16. <java.version>1.8java.version>
    17. <project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
    18. <project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
    19. <spring-cloud.version>Hoxton.SR8spring-cloud.version>
    20. <spring-cloud-alibaba.version>2.2.3.RELEASEspring-cloud-alibaba.version>
    21. properties>
    22. <dependencyManagement>
    23. <dependencies>
    24. <dependency>
    25. <groupId>org.springframework.cloudgroupId>
    26. <artifactId>spring-cloud-dependenciesartifactId>
    27. <version>${spring-cloud.version}version>
    28. <type>pomtype>
    29. <scope>importscope>
    30. dependency>
    31. <dependency>
    32. <groupId>com.alibaba.cloudgroupId>
    33. <artifactId>spring-cloud-alibaba-dependenciesartifactId>
    34. <version>${spring-cloud-alibaba.version}version>
    35. <type>pomtype>
    36. <scope>importscope>
    37. dependency>
    38. dependencies>
    39. dependencyManagement>
    40. project>

    创建商品微服务

    创建shop-product-api项目, 存放商品的实体类

    0>建成之后代码结构

    1>选择shop-parent,创建其子项目:shop-product-api

     2>在项目pom.xml文件导入依赖

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <parent>
    6. <artifactId>shop-parentartifactId>
    7. <groupId>com.langfeiyesgroupId>
    8. <version>1.0.0version>
    9. parent>
    10. <modelVersion>4.0.0modelVersion>
    11. <artifactId>shop-product-apiartifactId>
    12. <dependencies>
    13. <dependency>
    14. <groupId>com.baomidougroupId>
    15. <artifactId>mybatis-plus-boot-starterartifactId>
    16. <version>3.4.0version>
    17. dependency>
    18. <dependency>
    19. <groupId>org.projectlombokgroupId>
    20. <artifactId>lombokartifactId>
    21. dependency>
    22. dependencies>
    23. project>

    3>创建实体类

    1. //商品
    2. @Getter
    3. @Setter
    4. @ToString
    5. @TableName("t_product")
    6. public class Product implements Serializable {
    7. @TableId(type= IdType.AUTO)
    8. private Long id;//主键
    9. private String pname;//商品名称
    10. private Double pprice;//商品价格
    11. private Integer stock;//库存
    12. }

    4>创建shop-product-server项目

    5>在shop-product-server项目pom.xml文件中导入xml依赖

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <parent>
    6. <artifactId>shop-parentartifactId>
    7. <groupId>com.langfeiyesgroupId>
    8. <version>1.0.0version>
    9. parent>
    10. <modelVersion>4.0.0modelVersion>
    11. <artifactId>shop-product-serverartifactId>
    12. <dependencies>
    13. <dependency>
    14. <groupId>org.springframework.bootgroupId>
    15. <artifactId>spring-boot-starter-webartifactId>
    16. dependency>
    17. <dependency>
    18. <groupId>mysqlgroupId>
    19. <artifactId>mysql-connector-javaartifactId>
    20. dependency>
    21. <dependency>
    22. <groupId>com.alibabagroupId>
    23. <artifactId>fastjsonartifactId>
    24. <version>1.2.56version>
    25. dependency>
    26. <dependency>
    27. <groupId>com.langfeiyesgroupId>
    28. <artifactId>shop-product-apiartifactId>
    29. <version>1.0.0version>
    30. dependency>
    31. dependencies>
    32. project>

     6>在shop-product-server项目resources文件夹创建application.yml文件

    1. server:
    2. port: 8081
    3. spring:
    4. application:
    5. name: product-service
    6. datasource:
    7. driver-class-name: com.mysql.cj.jdbc.Driver
    8. url: jdbc:mysql:///shop-product?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    9. username: root
    10. password: admin

    7>在数据库中创建shop-order的数据库

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

    8>创建ProductMapper

    1. package com.langfeiyes.mapper;
    2. import com.langfeiyes.domain.Product;
    3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    4. public interface ProductMapper extends BaseMapper {
    5. }

    9>创建ProductService接口和实现类

    1. package com.langfeiyes.service;
    2. import com.langfeiyes.domain.Product;
    3. import com.baomidou.mybatisplus.extension.service.IService;
    4. public interface IProductService extends IService {
    5. }
    1. package com.langfeiyes.service.impl;
    2. import com.langfeiyes.domain.Product;
    3. import com.langfeiyes.mapper.ProductMapper;
    4. import com.langfeiyes.service.IProductService;
    5. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    6. import org.springframework.stereotype.Service;
    7. @Service
    8. public class ProductServiceImpl extends ServiceImpl implements IProductService {
    9. }

    10>创建Controller

    1. package com.langfeiyes.controller;
    2. @RestController
    3. @Slf4j
    4. public class ProductController {
    5. @Autowired
    6. private ProductService productService;
    7. //商品信息查询
    8. @RequestMapping("/product/{pid}")
    9. public Product findByPid(@PathVariable("pid") Long pid) {
    10. log.info("接下来要进行{}号商品信息的查询", pid);
    11. Product product = productService.findByPid(pid);
    12. log.info("商品信息查询成功,内容为{}", JSON.toJSONString(product));
    13. return product;
    14. }
    15. }

    11>编写启动类ProductServer.java

    1. package com.langfeiyes;
    2. import org.mybatis.spring.annotation.MapperScan;
    3. import org.springframework.boot.SpringApplication;
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;
    5. @SpringBootApplication
    6. @MapperScan("com.langfeiyes.mapper")
    7. public class ProductServer {
    8. public static void main(String[] args) {
    9. SpringApplication.run(ProductServer.class,args);
    10. }
    11. }

    10.通过浏览器访问服务

    创建订单微服务

    创建订单服务跟商品服务一样,就省略相同结构

    0>建成之后项目结构

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

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <parent>
    6. <artifactId>shop-parentartifactId>
    7. <groupId>com.langfeiyesgroupId>
    8. <version>1.0.0version>
    9. parent>
    10. <modelVersion>4.0.0modelVersion>
    11. <artifactId>shop-order-apiartifactId>
    12. <dependencies>
    13. <dependency>
    14. <groupId>com.baomidougroupId>
    15. <artifactId>mybatis-plus-boot-starterartifactId>
    16. <version>3.4.0version>
    17. dependency>
    18. <dependency>
    19. <groupId>org.projectlombokgroupId>
    20. <artifactId>lombokartifactId>
    21. dependency>
    22. dependencies>
    23. project>

    2>创建实体类

    1. package com.langfeiyes.domain;
    2. import com.baomidou.mybatisplus.annotation.IdType;
    3. import com.baomidou.mybatisplus.annotation.TableId;
    4. import lombok.Getter;
    5. import lombok.Setter;
    6. import java.io.Serializable;
    7. //订单
    8. @Getter
    9. @Setter
    10. @ToString
    11. @TableName("t_order")
    12. public class Order implements Serializable {
    13. @TableId(type = IdType.AUTO)
    14. private Long id;//订单id
    15. //用户
    16. private Long uid;//用户id
    17. private String username;//用户名
    18. //商品
    19. private Long pid;//商品id
    20. private String productName;//商品名称
    21. private Double productPrice;//商品单价
    22. //数量
    23. private Integer number;//购买数量
    24. }

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

    1. "1.0" encoding="UTF-8"?>
    2. <project xmlns="http://maven.apache.org/POM/4.0.0"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    5. <parent>
    6. <artifactId>shop-parentartifactId>
    7. <groupId>com.langfeiyesgroupId>
    8. <version>1.0.0version>
    9. parent>
    10. <modelVersion>4.0.0modelVersion>
    11. <artifactId>shop-order-serverartifactId>
    12. <dependencies>
    13. <dependency>
    14. <groupId>org.springframework.bootgroupId>
    15. <artifactId>spring-boot-starter-webartifactId>
    16. dependency>
    17. <dependency>
    18. <groupId>mysqlgroupId>
    19. <artifactId>mysql-connector-javaartifactId>
    20. dependency>
    21. <dependency>
    22. <groupId>com.alibabagroupId>
    23. <artifactId>fastjsonartifactId>
    24. <version>1.2.56version>
    25. dependency>
    26. <dependency>
    27. <groupId>com.langfeiyesgroupId>
    28. <artifactId>shop-order-apiartifactId>
    29. <version>1.0.0version>
    30. dependency>
    31. dependencies>
    32. project>

    4>编写配置文件application.yml

    1. server:
    2. port: 8091
    3. spring:
    4. application:
    5. name: order-service
    6. datasource:
    7. driver-class-name: com.mysql.cj.jdbc.Driver
    8. url: jdbc:mysql:///shop-order?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
    9. username: root
    10. password: admin

    5>在数据库中创建shop-order的数据库并创建t_order表

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

    6>创建OrderMapper

    1. package com.langfeiyes.mapper;
    2. import com.langfeiyes.domain.Order;
    3. import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    4. public interface OrderMapper extends BaseMapper {
    5. }

    7>创建OrderService接口和实现类

    1. package com.langfeiyes.service;
    2. import com.langfeiyes.domain.Order;
    3. import com.baomidou.mybatisplus.extension.service.IService;
    4. public interface IOrderService extends IService {
    5. }
    1. package com.langfeiyes.service.impl;
    2. import com.langfeiyes.domain.Order;
    3. import com.langfeiyes.mapper.OrderMapper;
    4. import com.langfeiyes.service.IOrderService;
    5. import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
    6. import org.springframework.stereotype.Service;
    7. @Service
    8. public class OrderServiceImpl extends ServiceImpl implements IOrderService {
    9. }

    8>创建Controller

    1. @RestController
    2. @RequestMapping("orders")
    3. public class OrderController {
    4. @Autowired
    5. private IOrderService orderService;
    6. @GetMapping("/save") //测试方便使用Get方式
    7. public Order order(Long pid, Long uid){
    8. return orderService.createOrder(pid, uid);
    9. }
    10. }

    9>编写启动类OrderServer.java

    1. package com.langfeiyes;
    2. import org.mybatis.spring.annotation.MapperScan;
    3. import org.springframework.boot.SpringApplication;
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;
    5. @SpringBootApplication
    6. @MapperScan("com.langfeiyes.mapper")
    7. public class OrderServer {
    8. public static void main(String[] args) {
    9. SpringApplication.run(OrderServer.class,args);
    10. }
    11. }

    订单服务远程调用

    需求:定义createOrder方法,实现用户下订单

    在shop-order-server项目的IOrderService 接口定义createOrder方法

    1. public interface IOrderService extends IService {
    2. /**
    3. * 创建订单
    4. * @param pid
    5. * @param uid
    6. * @return
    7. */
    8. Order createOrder(Long pid, Long uid);
    9. }

    OrderServiceImpl 实现类实现IOrderService  接口方法

    1. @Service
    2. public class OrderServiceImpl extends ServiceImpl implements IOrderService {
    3. @Override
    4. public Order createOrder(Long pid, Long uid) {
    5. Order order = new Order();
    6. //商品??
    7. Product product = null;
    8. order.setPid(pid);
    9. order.setProductName(product.getName());
    10. order.setProductPrice(product.getPrice());
    11. //用户
    12. order.setUid(1L);
    13. order.setUsername("dafei");
    14. order.setNumber(1);
    15. super.save(order);
    16. return order;
    17. }
    18. }

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

    思考,谁能提供商品信息查询逻辑呢?答案:product-server, 问题来了,怎么调用?这里引入一个新问题:服务与服务间如何调用(交互)?

    问题来了,怎么用java代码调用发起http接口调用嗯??答案是:RestTemplate

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

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

    1. @SpringBootApplication
    2. @MapperScan("com.langfeiyes.mapper")
    3. public class OrderServer {
    4. public static void main(String[] args) {
    5. SpringApplication.run(OrderServer.class,args);
    6. }
    7. @Bean
    8. public RestTemplate restTemplate(){
    9. return new RestTemplate();
    10. }
    11. }

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

    1. @Service
    2. public class OrderServiceImpl extends ServiceImpl implements IOrderService {
    3. @Autowired
    4. private RestTemplate restTemplate;
    5. @Override
    6. public Order createOrder(Long pid, Long uid) {
    7. Order order = new Order();
    8. //商品
    9. //方案1:通过restTemplate方式
    10. String url = "http://localhost:8081/products/" + pid;
    11. Product product = restTemplate.getForObject(url, Product.class);
    12. order.setPid(pid);
    13. order.setProductName(product.getName());
    14. order.setProductPrice(product.getPrice());
    15. //用户
    16. order.setUid(1L);
    17. order.setUsername("dafei");
    18. order.setNumber(1);
    19. System.out.println(order);
    20. super.save(order);
    21. return order;
    22. }
    23. }

    3>启动OrderServer服务器,访问: http://localhost:8091/orders/save?pid=1&uid=1

    实现订单添加。

    最后

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

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

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

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

    那怎么办呢,请听下回分解~

     看文字不过瘾可以切换视频版:SpringCloud Alibaba 极简入门

  • 相关阅读:
    请输入一个整数
    高性能数据访问中间件 OBProxy(六):一文讲透数据路由
    java ThreadPoolExecutor 分析
    Vue的详细教程--用Vue-cli搭建SPA项目
    2022年五款适合新手入门的吉他推荐,超全面吉他选购攻略防雷不踩坑!
    SQL 之 ROW_NUMBER() OVER函数用法
    mysql数据库扫盲,你真的知道什么是数据库嘛
    hadoop2.2.0开机启动的后台服务脚本(请结合上一篇学习)
    python小玩意——计算器
    线性代数(六) 线性变换
  • 原文地址:https://blog.csdn.net/langfeiyes/article/details/127420795