2.服务拆分和服务调用
本文的视频链接:01-今日课程介绍_哔哩哔哩_bilibili
参考链接:(10条消息) SpringCloud笔记(黑马)_安赫'的博客-CSDN博客
2.1 服务拆分原则
-
不同微服务,不要重复开发相同业务;
-
微服务数据独立,不要访问其它微服务的数据库;
-
微服务可以将自己的业务暴露为接口,供其它微服务调用。

2.2 服务拆分案例
这里以黑马的微服务cloud-demo为例,进行项目复用。
cloud-demo:父工程,管理依赖
-
order-service:订单微服务,负责订单相关业务;
-
user-service:用户微服务,负责用户相关业务;
要求:
-
订单微服务和用户微服务必须有各自的数据库,相互独立;
-
订单服务和用户服务都对外暴露Restful的接口;
-
订单服务如果要查询用户信息,只能调用用户服务的Restful接口,不能查询用户数据库。
2.2.1 从零开始搭建SpringCloud项目
创建项目:
首先在Idea中new一个Maven项目,在GroupId中填入包名,ArtifastId填写项目名,然后选择电脑中一个文件夹来创建该项目。

创建好的项目如下:

由于主项目中,我们是不写代码的,因此将该项目中的src包直接删除,再导入order-service和user-service模块。

导入项目依赖:
导入父项目依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.ku</groupId> <artifactId>cloud-demo</artifactId> <packaging>pom</packaging> <version>1.0</version> <modules> <module>order-service</module> <module>user-service</module> </modules> <!--父依赖--> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.3.9.RELEASE</version> <relativePath/> </parent> <!--依赖属性--> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR10</spring-cloud.version> <!--<mysql.version>5.1.47</mysql.version>--> <!--<mybatis.version>2.1.1</mybatis.version>--> </properties> <dependencyManagement> <dependencies> <!-- springCloud --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--nacos的管理依赖--> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>2.2.5.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> <!-- mysql驱动 --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.17</version> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.0</version> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> </dependency> </dependencies> </project>
导入order-service项目依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud-demo</artifactId> <groupId>com.ku</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>order-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> </dependencies> <!--打包--> <build> <finalName>order-app</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
导入user-service项目依赖:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>cloud-demo</artifactId> <groupId>com.ku</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>user-service</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <!--mybatis--> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> </dependencies> <!--打包--> <build> <finalName>user-app</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
创建两个服务模块结构流程:
-
分别创建OrderServiceApplication和UserServiceApplciation两个启动类
-
创建order-service和user-service的四层结构(pojo、mapper、service、controller,其中Order类中引入User类,后面会改进)
-
首先创建两个模块的数据库,然后执行两个模块的SQL语句,生成对应的数据表
-
分别配置两个模块的application.yml文件
#order-service配置文件
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://localhost:3306/cloud_order?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: com.ku.order.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.ku.order: debug
#user-service配置文件
server:
port: 8081
spring:
datasource:
url: jdbc:mysql://localhost:3306/cloud_user?useSSL=false
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
mybatis:
type-aliases-package: cn.ku.user.pojo
configuration:
map-underscore-to-camel-case: true
logging:
level:
com.ku.user: debug
pattern:
dateformat: MM-dd HH:mm:ss:SSS
在启动多模块项目的时候,会出现以下弹窗,我们点集弹窗,选择第一个,就会出现多模块运行窗口了



2.3 实现远程调用案例
2.3.1 Order-service查询测试

当我们通过订单号区查询订单信息的时候,由于我们的订单数据库中只存储了用户ID,且每个服务之间是相互独立的,因此无法查询到用户相关信息。
2.3.2 RestTenplate远程调用流程
在上一节中,我们由于服务模块之间相互独立,通过order模块无法查询到用户模块的用户信息,本节我们将通过远程调用,通过user-service暴露的接口查询出订单实体类中的是所有属性信息。
我们需要在order-service中向user-service发起一个http请求,调用http://localhost:8081/user/{userId}这个接口。
-
注册一个RestTemplate的实例到Spring容器中,即向OrderServiceApplication注册一个RestTemplate的bean;
-
修改order-service服务中的queryOrderById方法,根据Order对象中的uerId查询User;
-
将查询的User填充到Order对象中,一起返回。
2.3.3 注册 RestTenplate
我们需要在order-service的OrderServiceApplication启动类中,注册RestTemplate实例
@MapperScan("com.ku.order.mapper")
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
//远程调用
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
2.3.4 实现远程调用
修改order-service服务中的com.ku.order.service中OrderService类中的queryOrderById()方法
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.利用RestTemplate发起http请求,查询用户
// 2.1.url路径
String url = "http://localhost:8081/user/" + order.getUserId();
// 2.2.发送http请求,实现远程调用
User user = restTemplate.getForObject(url, User.class);
// 3.封装user到Order
order.setUser(user);
// 4.返回
return order;
}
上述代码重点在于RestTemplate对象通过传入的url和希望获取的实体类到getForObject()方法从而获取用户模块的用户信息。
测试结果:

小结:
-
基于RestTemplate发起的Http请求实现远程调用;
-
http请求做远程调用是与语言无关的调用,只要知道对方的ip、端口、接口路径、请求参数即可。
2.4 提供者与消费者
在服务调用关系中,会有两个不同的角色:
服务提供者:一次业务中,被其它微服务调用的服务。(提供接口给其它微服务)
服务消费者:一次业务中,调用其它微服务的服务。(调用其它微服务提供的接口)
但是,服务提供者与服务消费者的角色并不是绝对的,而是相对于业务而言。
思考:如果服务A调用了服务B,而服务B又调用了服务C,服务B的角色是什么?
对于A调用B的业务而言:A是服务消费者,B是服务提供者 对于B调用C的业务而言:B是服务消费者,C是服务提供者 因此,服务B既可以是服务提供者,也可以是服务消费者。
服务调用关系:
-
服务提供者:暴露接口给其他服务调用
-
服务消费者:调用其他微服务提供的接口
-
提供者与消费者是相对的
-
一个服务可以同时是服务提供者和服务消费者
浙公网安备 33010602011771号