当前位置: 首页 > news >正文

【微服务】(2) 环境和工程搭建

        先安装好 JDK 和 MySQL。

一、案例介绍

        以电商平台为例,有很多业务:用户、订单、秒杀、搜索……该服务巨大,微服务是更好的选择。

1、服务拆分原则

        并不是越细越好,越细带来的管理困难也就越高。

  • 单一职责,效率更高。
  • 服务自治,互相影响更小。每个服务都能独立开发、测试、构建、部署、运行。
  • 单向依赖,禁止循环、双向依赖。无法避免时,可用其他技术如消息队列解耦。

2、服务拆分示例

        对于订单列表:

        ① 单一职责:拆分为订单服务、商品服务(实际项目划分更细)。

        ② 服务自治:每个服务创建独立数据库。

        订单表:

-- 建库
create database if not exists cloud_order charset utf8mb4;
-- 订单表
DROP TABLE IF EXISTS order_detail;
CREATE TABLE order_detail (`id` INT NOT NULL AUTO_INCREMENT COMMENT '订单id',`user_id` BIGINT ( 20 ) NOT NULL COMMENT '⽤⼾ID',`product_id` BIGINT ( 20 ) NULL COMMENT '产品id',`num` INT ( 10 ) NULL DEFAULT 0 COMMENT '下单数量',`price` BIGINT ( 20 ) NOT NULL COMMENT '实付款',`delete_flag` TINYINT ( 4 ) NULL DEFAULT 0,`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( id )) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8mb4 COMMENT = '订单表';
-- 数据初始化
insert into order_detail (user_id,product_id,num,price)
values
(2001, 1001,1,99), (2002, 1002,1,30), (2001, 1003,1,40),
(2003, 1004,3,58), (2004, 1005,7,85), (2005, 1006,7,94);

        商品表:

create database if not exists cloud_product charset utf8mb4;
-- 产品表
DROP TABLE IF EXISTS product_detail;
CREATE TABLE product_detail (`id` INT NOT NULL AUTO_INCREMENT COMMENT '产品id',`product_name` varchar ( 128 ) NULL COMMENT '产品名称',`product_price` BIGINT ( 20 ) NOT NULL COMMENT '产品价格',`state` TINYINT ( 4 ) NULL DEFAULT 0 COMMENT '产品状态 0-有效 1-下架',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now(),
PRIMARY KEY ( id )) ENGINE = INNODB DEFAULT CHARACTER
SET = utf8mb4 COMMENT = '产品表';
-- 数据初始化
insert into product_detail (id, product_name,product_price,state)
values
(1001,"T恤", 101, 0), (1002, "短袖",30, 0), (1003, "短裤",44, 0), 
(1004, "卫⾐",58, 0), (1005, "⻢甲",98, 0),(1006,"⽻绒服", 101, 0), 
(1007, "冲锋⾐",30, 0), (1008, "袜⼦",44, 0), (1009, "鞋⼦",58, 0),
(10010, "⽑⾐",98, 0)

        可能会出现错误:

        这是客户端编码跟表编码不一致的锅,在建库前加一句:

SET NAMES utf8mb4;

二、工程搭建

1、构建父子工程

(1)构建父项目

  • 父工程负责管理子模块依赖,不负责编译生成可执行文件,因此只需保留 pom.xml 文件。

        创建空 maven 项目,删除所有源代码,只保留 pom.xml 文件

        完善 pom 文件:

  • 父工程的打包方式是 pom 而不是 jar,因此需要手动声明以 pom 方式打包
  • 父工程依赖 Sring Boot 父工程,需要 <parent> 声明父工程
  • <properties> 管理依赖的版本号,注意 spring cloud 版本与 spring boot 版本匹配。
  • <dependencies> jar 包直接放到项目中,子项目直接继承
  • <dependencyManagement> 声明依赖,没有引入 jar 包,子项目想引入 jar 需要显示声明。若子项目指定版本号,按指定版本引入;若子项目没有指定版本按父工程管理的版本号来。
    <!-- 声明当前工程包含哪些子工程,创建子工程时会自动添加到当前工程中--><modules><module>order-service</module><module>product-service</module></modules><!-- 声明以 pom 方式打包 --><packaging>pom</packaging><!-- 继承官方的 Spring Boot 父工程,引入 Spring Boot 常用依赖无需手动指定版本号--><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.1.6</version><relativePath/></parent><!-- 声明管理依赖的版本号--><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><java.version>17</java.version><mybatis.version>3.0.3</mybatis.version><mysql.version>8.0.33</mysql.version><spring-cloud.version>2022.0.3</spring-cloud.version></properties><!-- 引入依赖,子工程继承父工程的依赖,无需重复引入--><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><!-- 声明依赖,子工程引入依赖时,可无需指定版本号,由父工程统一管理--><dependencyManagement><dependencies><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>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><version>${mysql.version}</version></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter-test</artifactId><version>${mybatis.version}</version><scope>test</scope></dependency></dependencies></dependencyManagement>

        因为<dependencyManagement> 只是声明,没有真正引入 jar 包,所以爆红了很正常,不用管。上面的依赖没有爆红,是因为我之前下载到本地仓库过:

(2)构建子项目:订单、商品服务

        创建新模块:

        引入项目依赖和项目构建插件,这里就不用指定版本号,直接继承父工程的依赖版本号管理:

    <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId></dependency><!--mybatis--><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>

2、完善子项目服务

  • 启动类
package com.pygymi.order;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class OrderServiceApplication {public static void main(String[] args) {SpringApplication.run(OrderServiceApplication.class, args);}
}
  • 配置文件
#应用端口号
server:port: 8080
# 数据库连接配置
spring:datasource:url: jdbc:mysql://127.0.0.1:3306/cloud_order?characterEncoding=utf8&useSSL=false&allowPublicKeyRetrieval=trueusername: rootpassword: "123456"driver-class-name: com.mysql.jdbc.Driver
# mybatis配置
mybatis:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印日志map-underscore-to-camel-case: true # 配置驼峰⾃动转换
  • 完善订单服务业务代码:

        实体类:

@Data
public class OrderInfo {private Integer id;private Integer userId;private Integer productId;private Integer num;private Integer price;private Integer deleteFlag;private Date createTime;private Date updateTime;
}

        controller:

@RestController
@RequestMapping("/order")
public class OrderController {@Resource(name = "orderServiceImpl")private OrderService orderService;@GetMapping("/{orderId}")public OrderInfo getOrder(@PathVariable("orderId") String orderId) {return orderService.getOrder(orderId);}
}

        service:

public class OrderServiceImpl implements OrderService {@Resourceprivate OrderMapper orderMapper;@Overridepublic OrderInfo getOrder(String orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);return orderInfo;}
}

        mapper:

public interface OrderMapper {@Select("SELECT * FROM order_info WHERE id = #{orderId}")OrderInfo selectOrderById(String orderId);
}
  • 完善商品服务业务代码:同理。
  • 接口测试:

        订单查询:127.0.0.1:8080/order/1

        商品查询:127.0.0.1:9090/product/1001

3、远程调用

        查询订单信息时,需要查询商品的详细信息,解决办法是:订单服务通过 HTTP 访问商品服务,获取到商品详情放到订单返回结果中。

        实现方式使用 Spring 提供的 RestTemplate。

        定义 RestTemplate,因为五大注入 bean 的注解修饰的是类,RestTemplate 是别人写的类我们无法修改,所以使用方法注入 @Bean:

@Configuration
public class BeanConfig {@Beanpublic RestTemplate restTemplate() {return new RestTemplate();}
}

        在订单服务中,通过 HTTP 访问商品服务:

@Service
public class OrderServiceImpl implements OrderService {@Resourceprivate OrderMapper orderMapper;@Resourceprivate RestTemplate restTemplate;@Overridepublic OrderInfo getOrder(String orderId) {OrderInfo orderInfo = orderMapper.selectOrderById(orderId);// 构造访问商品服务的 urlString url = "http://127.0.0.1:9090/product/" + orderInfo.getProductId();// 使用 restTemplate 访问商品服务ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);// 把商品详情设置到 orderInfo 中orderInfo.setProductInfo(productInfo);return orderInfo;}
}

        测试:127.0.0.1:8080/order/1

三、RestTemplate

1、REST

        REST(表现层资源状态转移)是一种设计风格,指网络资源以某种表现形式进行状态转移。

  • 资源:网络上的所有数据,如图像、视频、文本等。
  • 表现层:资源的表现形式,如 jpg、txt、json 等。
  • 状态转移:通过网络访问资源,对资源进行修改(增删改查),都会引起资源状态转移。

2、RESTful API

        满足 REST 设计风格的接口都叫做 RESTful API。其特性:

  • 统一接口:对资源的操作,对应 HTTP 协议提供的 GET、POST、PUT、DELETE。

        如:GET /blog/{blogId}:查询博客

        使用 REST 风格实现的接口,我们只能从 URL 定位其资源,并不能直接知晓其是什么操作,想要知道还需要用抓包工具查看请求,得知 GET、POST……

3、RestTemplate

        就是 Spring 实现的,强制使用 RESTsul 风格的 HTTP 调用模板。我们只需要提供资源地址和参数类型。

4、RESTful 风格缺点

  • 想知道该接口对资源执行了什么操作,还要先抓包,不方便团队理解和交流。
  • 一些旧浏览器对 GET、POST 以外的请求支持不太友好。
  • 复杂的业务强行使用 RESTful 风格反而增加开发难度,因为不能仅仅使用增删改查实现。

四、项目存在的问题

  • 远程调用时,被调用方的 IP 是写死的,IP 容易写错,也容易在源代码基础上修改。我们希望不依赖提供方的 IP。
  • 所有服务都可以调用该接口,具有风险。
  • 多机部署,没有实现压力分摊。

…… 后续继续学习 spring cloud 的各种组件,来解决这些问题。

http://www.dtcms.com/a/503091.html

相关文章:

  • 做网站工具 不懂代码网站开发项目交接
  • 外贸网站推广平台哪个好网站建设公司相关资质
  • 2025年智能Agent终极指南:从概念到高效营销工具
  • 网络安全 | 深入了解 X.509 证书及其应用
  • Token快过期的三种续期方案
  • 网站建设html代码优化广东新闻联播今天
  • 微服务之配置中心Nacos
  • 好网站推荐娄底高端网站建设
  • h5游戏免费下载:保卫机器人
  • 如何解决 pip install -r requirements.txt 私有索引未设为 trusted-host 导致拒绝 问题
  • Redis(71)如何确保Redis分布式锁的可靠性?
  • docker安装php+apache
  • 数据查询网站包装设计公司排行榜
  • [JavaEE初阶]网络协议-状态码
  • 5.2 UDP (答案见原书 P230)
  • 做资讯类网站需要什么资质宁波seo推广公司电话
  • 第十五部分:信号量和读写锁
  • 无刷直流电机(BLDC)数学模型深度解析
  • 第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第二赛季--最后一题解读
  • Spring Boot 3零基础教程,WEB 开发 内容协商源码分析 默认的 HttpMessageConverter 自定义返回值格式 笔记34
  • 【嵌入式面试题】STM32F103C8T6 完整元器件解析 + 面试问题答案
  • docker入门教程--部署nginx和tomcat
  • 3.1.2 从NoSQL到图数据库的转型
  • 【洛谷】哈希表实战:5 道经典算法题(unordered_map/set 应用 + 避坑指南)
  • 昆明 网站推广营销策划公司简介
  • 医院做网站是最简单的前端吗长沙水业网站是哪家公司做的
  • GridPlayer,一个好用的多视频同步播放器
  • 用 Go 语言实现《周易》大衍筮法起卦程序
  • 2025年渗透测试面试题总结-209(题目+回答)
  • 深度学习6-激活函数-参数初始化和正则化-搭建神经网络-损失函数