一.什么是微服务?

微服务≠springcloud,是一种经过良好架构设计的分布式解决方案,微服务架构特征

单一职责:微服务拆分力度更小,每一个服务都对应唯一的业务能力,做到单一职责,避免重复业务开发面向服务:微服务对外暴露业务接口自治:团队独立,技术独立,数据独立,部署独立,每个服务有自己独立的数据库隔离性强:服务调用做好隔离,容错,降级,避免出现级联问题

单体架构

将业务的所有的功能集成到一个项目中开发,打成一个包部署

优点:

架构简单部署成本低适合面向企业内部的小项目

缺点:

耦合度高

分布式架构

根据业务功能对系统进行拆分,每个业务模块作为独立项目开发,称为一个服务。

优点:

降低了耦合度有利于服务的拓展升级

二.springcluod

springcluod是目前全球使用最广泛的微服务框架,集成了各种微服务功能组件,并基于springboot实现了这些组件的自动装配 springcloud与springboot的兼容版本

2.1服务的拆分及远程架构

服务拆分

不同的微服务,不开发重复的功能微服务数据库独立,不要访问其他微服务的数据库微服务可以将自己的业务暴露为接口,供其他微服务调用

创建数据库以及执行sql语句的小插曲

  创建数据库时,编码使用utf8mb4(我的mysql版本是8.0.33),而给定的资料中是用5版本的mysql导出的sql脚本,因此直接运行可能有些问题。主要是字符集和排序规则的问题,MySQL 8.0 会自动将会话字符集设置为 utf8mb4,因此不需要再手动设置 SET NAMES utf8mb4;mysql5.0常用的字符集是utf8,因此导出的内容可能也涉及utf8字符集的设置,修改为适合MySQL 8.0的utf8mb4即可;另外,不需要再在表级别上设置utf8mb4字符集以及排序规则,我整理了适合5版本以及8版本两个版本的sql脚本

2.1.1 服务拆分的准备工作

cloud-order数据库 MySQL 5.0版本

-- cloud-order数据库 MySQL 5.0版本

SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for tb_order

-- ----------------------------

DROP TABLE IF EXISTS `tb_order`;

CREATE TABLE `tb_order` (

`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',

`user_id` bigint(20) NOT NULL COMMENT '用户id',

`name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '商品名称',

`price` bigint(20) NOT NULL COMMENT '商品价格',

`num` int(10) NULL DEFAULT 0 COMMENT '商品数量',

PRIMARY KEY (`id`) USING BTREE,

UNIQUE INDEX `username`(`name`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------

-- Records of tb_order

-- ----------------------------

INSERT INTO `tb_order` VALUES (101, 1, 'Apple 苹果 iPhone 12 ', 699900, 1);

INSERT INTO `tb_order` VALUES (102, 2, '雅迪 yadea 新国标电动车', 209900, 1);

INSERT INTO `tb_order` VALUES (103, 3, '骆驼(CAMEL)休闲运动鞋女', 43900, 1);

INSERT INTO `tb_order` VALUES (104, 4, '小米10 双模5G 骁龙865', 359900, 1);

INSERT INTO `tb_order` VALUES (105, 5, 'OPPO Reno3 Pro 双模5G 视频双防抖', 299900, 1);

INSERT INTO `tb_order` VALUES (106, 6, '美的(Midea) 新能效 冷静星II ', 544900, 1);

INSERT INTO `tb_order` VALUES (107, 2, '西昊/SIHOO 人体工学电脑椅子', 79900, 1);

INSERT INTO `tb_order` VALUES (108, 3, '梵班(FAMDBANN)休闲男鞋', 31900, 1);

SET FOREIGN_KEY_CHECKS = 1;

cloud-order数据库 MySQL 8.0版本

-- cloud-order数据库 MySQL 8.0版本

-- SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for tb_order

-- ----------------------------

DROP TABLE IF EXISTS `tb_order`;

CREATE TABLE `tb_order` (

`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '订单id',

`user_id` bigint(20) NOT NULL COMMENT '用户id',

`name` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '商品名称',

`price` bigint(20) NOT NULL COMMENT '商品价格',

`num` int(10) NULL DEFAULT 0 COMMENT '商品数量',

PRIMARY KEY (`id`) USING BTREE,

UNIQUE INDEX `username`(`name`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 109 ROW_FORMAT = Compact;

-- ----------------------------

-- Records of tb_order

-- ----------------------------

INSERT INTO `tb_order` VALUES (101, 1, 'Apple 苹果 iPhone 12 ', 699900, 1);

INSERT INTO `tb_order` VALUES (102, 2, '雅迪 yadea 新国标电动车', 209900, 1);

INSERT INTO `tb_order` VALUES (103, 3, '骆驼(CAMEL)休闲运动鞋女', 43900, 1);

INSERT INTO `tb_order` VALUES (104, 4, '小米10 双模5G 骁龙865', 359900, 1);

INSERT INTO `tb_order` VALUES (105, 5, 'OPPO Reno3 Pro 双模5G 视频双防抖', 299900, 1);

INSERT INTO `tb_order` VALUES (106, 6, '美的(Midea) 新能效 冷静星II ', 544900, 1);

INSERT INTO `tb_order` VALUES (107, 2, '西昊/SIHOO 人体工学电脑椅子', 79900, 1);

INSERT INTO `tb_order` VALUES (108, 3, '梵班(FAMDBANN)休闲男鞋', 31900, 1);

SET FOREIGN_KEY_CHECKS = 1;

运行结果

cloud-user数据库 MySQL 5.0版本

SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for tb_user

-- ----------------------------

DROP TABLE IF EXISTS `tb_user`;

CREATE TABLE `tb_user` (

`id` bigint(20) NOT NULL AUTO_INCREMENT,

`username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '收件人',

`address` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '地址',

PRIMARY KEY (`id`) USING BTREE,

UNIQUE INDEX `username`(`username`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 109 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;

-- ----------------------------

-- Records of tb_user

-- ----------------------------

INSERT INTO `tb_user` VALUES (1, '柳岩', '湖南省衡阳市');

INSERT INTO `tb_user` VALUES (2, '文二狗', '陕西省西安市');

INSERT INTO `tb_user` VALUES (3, '华沉鱼', '湖北省十堰市');

INSERT INTO `tb_user` VALUES (4, '张必沉', '天津市');

INSERT INTO `tb_user` VALUES (5, '郑爽爽', '辽宁省沈阳市大东区');

INSERT INTO `tb_user` VALUES (6, '范兵兵', '山东省青岛市');

SET FOREIGN_KEY_CHECKS = 1;

cloud-user数据库 MySQL 8.0版本

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for tb_user

-- ----------------------------

DROP TABLE IF EXISTS `tb_user`;

CREATE TABLE `tb_user` (

`id` bigint(20) NOT NULL AUTO_INCREMENT,

`username` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '收件人',

`address` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '地址',

PRIMARY KEY (`id`) USING BTREE,

UNIQUE INDEX `username`(`username`) USING BTREE

) ENGINE = InnoDB AUTO_INCREMENT = 109 ROW_FORMAT = Compact;

-- ----------------------------

-- Records of tb_user

-- ----------------------------

INSERT INTO `tb_user` VALUES (1, '柳岩', '湖南省衡阳市');

INSERT INTO `tb_user` VALUES (2, '文二狗', '陕西省西安市');

INSERT INTO `tb_user` VALUES (3, '华沉鱼', '湖北省十堰市');

INSERT INTO `tb_user` VALUES (4, '张必沉', '天津市');

INSERT INTO `tb_user` VALUES (5, '郑爽爽', '辽宁省沈阳市大东区');

INSERT INTO `tb_user` VALUES (6, '范兵兵', '山东省青岛市');

SET FOREIGN_KEY_CHECKS = 1;

运行结果

微服务拆分Demo

1.准备工作

 1.创建2个不同的数据库cloud-order与cloud-user

 2.导入相应的sql文件  3.导入demo  4.运行两个服务端程序OrderApplication与UserApplication

2.准备工作运行结果

2.1.2 服务拆分

1.远程调用方式分析与案例 用户模块对外暴露接口@GetMapping(“/user/{id}”),只要能够发送HTTP请求即可请求目标地址并获得返回结果 使用RestTemplate对象,可以被直接注入,基础案例

@Service

public class OrderService {

@Autowired

private OrderMapper orderMapper;

@Autowired

private RestTemplate restTemplate;

public Order queryOrderById(Long orderId) {

// 1.查询订单

Order order = orderMapper.findById(orderId);

// 2.利用RestTemplate发送请求

String url="http://localhost:8081/user/"+order.getUserId();

User user=restTemplate.getForObject(url,User.class);

order.setUser(user);

// 4.返回

return order;

}

}

运行结果 2.提供者与消费者 提供者:暴露接口给别人调用 消费者:调用别人的接口 服务A调用服务B,服务B调用服务C,此时服务B既可以是提供者也是消费者。

3.Eureka注册中心原理

使用硬编码服务地址,后期有多个提供服务的人时,会造成问题…

Eureka的2个概念

eureka-server服务端,注册中心,记录和管理服务eureka-client客户端,无论是服务的提供者还是消费者,都是eureka的客户端

Eureka的使用流程

只要是eureka-client客户端,无论是服务的提供者还是消费者,在启动时都会被注册到eureka-server注册中心,当游人需要调用服务时,不是直接找服务的提供者,而是找Eureka-server,询问是否有相应的服务,Eureka-server找到之后会直接提供给对方。 然后使用负载均衡,在这些服务之中选择一个。为了保证不会找到挂掉的服务,Eureka每三十秒发送一次请求,如果有的服务没有响应,就认为该服务已经挂掉,将其从注册中心里边清除;

4.搭建Eureka服务

1.创建项目,导入依赖spring-cloud-starter-netflix-eureka-server(Eureka服务端依赖)

org.springframework.cloud

spring-cloud-starter-netflix-eureka-server

由于在父工程中已经指定了spring-cloud依赖库,所以里边的各种spring-cloud组件都已经被指定,因此子工程中eureka依赖不需要指定版本。

2.启动类添加@EnableEurekaServer注解,其作用是标识一个应用作为Eureka注册中心来使用

@EnableEurekaServer

@SpringBootApplication

public class EurekaApplication {

public static void main(String[] args) {

SpringApplication.run(EurekaApplication.class,args);

}

}

3.添加配置信息(**由于eureka本身也是一个微服务,所以在启动时会将自己也注册到eureka上,为了将来eureka集群的使用),需要特别注意设置fetch-registry为false ,否则会报错,因为此时并没有其他服务的信息,所以如果让它拉取会报错, register-with-eureka,fetch-registry默认都为true

server:

port: 10087 # 服务端口

spring:

application:

name: eurekaserver # 服务名称

# eureka服务注册信息

eureka:

client:

register-with-eureka: true # 是否注册自己的信息到EurekaServer

fetch-registry: false # 是否拉取其它服务的信息

service-url:

defaultZone: http://127.0.0.1:10087/eureka

运行结果: 注册到eureka的实例(一个服务每注册一份就是一个实例)

5.服务注册 1.导入依赖

org.springframework.cloud

spring-cloud-starter-netflix-eureka-client

2.新增配置,以user-service为例(只需要将服务名称改为对应的服务名称即可),其余同理

spring:

application:

name: userservice # user服务名称

# eureka服务注册信息

eureka:

client:

service-url:

defaultZone: http://127.0.0.1:10087/eureka

3.运行结果,可以看到已经注册了三个服务实例

6.同一个服务多次启动

这是我们当前IDEA的运行面板:

似乎并不是非常的方便,于是我们将其修改为Run Dashboard面板,点击下图所示的“服务”

添加springboot配置即可,运行结果(适用于2020,2021版本):

右键单击一个服务,以orderservice为例,点击“复制配置”

随后弹出窗口

由于启动同样的服务使用同样的端口会造成冲突,所以重新配置新的服务的端口为8082。

点击应用,启动之,运行结果:

此时,在eureka注册中心中配置了2个orderserivce服务

7.服务的发现

  比如在orderservice中完成服务拉取,“服务拉取”就是基于服务名称获取服务列表,然后对服务列表做负载均衡。

修改OrderService代码,修改访问的URL路径,用服务名代替IP,端口号

String url="http://userservice/user/"+order.getUserId();

在RestTemplate中添加负载均衡注解@LoadBalanced

@Bean //该方法会返回一个RestTemplate对象,并将其注册到spring容器中;

@LoadBalanced //告诉RestTemplate在执行HTTP请求时,应该采用负载均衡的方式;

public RestTemplate restTemplate(){

return new RestTemplate();

}

对RestTemplate对象的解释:

RestTemplate是Spring Framework中的一个核心类,用于进行HTTP请求与响应的交互。它提供了一种简单而强大的方式来访问RESTful服务,并处理与这些服务之间的通信;RestTemplate的主要功能有:1.发送HTTP请求,2.处理HTTP响应,3.允许设置请求的参数和请求体,4.提供了一些便捷的方法来简化HTTP请求的构建和处理,5.支持将HTTP响应转换成Java对象,可以通过设置不同的HttpMessageConverter来实现JSON、XML等格式的转换

好文链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。