文章目录
写在前面:
- Spring Cloud 中的服务调用方式为 RestFul,也就是本文所围绕内容的主题;
- 而可以与之对应的 Dubbo + Zookeeper 的服务调用方式为 RPC,我之前的一篇文章可供参考:SpringBoot集成 Dubbo + Zookeeper + Dubbo Admin:服务注册发现实战与详细步骤。
0 RestTemplate 简介
当我们在微服务项目开发中,从服务消费端去调用服务提供者的服务的时候,可借助 RestTemplate 类,RestTemplate 类封装提了许多访问远程 http 服务的方法,是一种简单的 Restful 服务模板。
1 【父工程】搭建
新建一个空的 Maven 工程作为父工程,将这个父工程的打包方式改为 pom (因为是在父级工程或聚合工程中,用来做jar包的版本控制)。
我们在学习阶段还是不要直接复制别人已经整理好的 dependency 了,争取自己去探索一下。
首先,我们先去 Spring Cloud 的文档中找一下,一般都是会给例子的(过不过时就不一定了,不过最起码我们可以得到一个 dependency 的模板)。
我们在 Spring Cloud 中文API文档 Ctrl + F,模糊查询一下,可以直接查到:
但我们发现,模板是有了,接下来就是看看版本合不合适,框中的版本信息:<version>Brixton.RELEASE</version>
,是 B 版本的,过于久远。至于 Spring Cloud 项目的版本,是从 A 开始到 Z 的顺序来命名的,而全拼又是以伦敦的地铁站的名字来命名,几个大版本的名字如下图(其实这张图也很旧了):
因此,我们就将版本那块的内容改为 G 版本就可以了。而具体是什么呢,我们可以去 Maven 仓库中查找,根据模板中的组件名为 spring-cloud-dependencies,我们先模糊查询。
版本我们选 H版 的 SR4(因为我现在跟着学的这个教程是用的这个版本,因此为了避免在学习阶段被过多的版本问题所困扰,先选一下这个版本来学习)
之后再添加一些必要的依赖,过程不再赘述,最终父工程的 pom 文件如下:
<?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.zlc</groupId>
<artifactId>mysrpingcloud</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>
<dependencyManagement>
<dependencies>
<!-- spring-cloud-dependencies -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR4</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- spring-boot-dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<!-- druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.22</version>
</dependency>
<!-- mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2 【数据库 与 子模块springcloud-api】搭建
2.1 数据库搭建
创建数据库 db01,在其中创建表 dept
随后插入几行数据,用于之后测试
2.2 项目搭建
新建一个名为 springcloud-api 的子模块(空 Maven),若当前 Module 自己需要的依赖,如果父依赖中配置了此依赖的版本(在 dependencyManagement 标签中),则不用再写,其 pom 文件内容如下:
<?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>mysrpingcloud</artifactId>
<groupId>com.zlc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-api</artifactId>
<!--当前 Module 自己需要的依赖,如果父依赖中配置了此依赖的版本,则不用再写-->
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
</project>
创建 JavaBean
需要序列化(实现 Serializable 接口),因为微服务项目中的实体类要通信传输
@Data
@NoArgsConstructor
@Accessors(chain = true) //链式写法
public class Dept implements Serializable {
private Long deptno; //主键
private String dname;
//这个数据存在哪个数据库的字段,微服务,一个服务对应一个数据库
//同一信息可能存在不同数据库
private String db_source;
public Dept(String dname) {
this.dname = dname;
}
/*
链式写法:
Dept dept = new Dept();
dept.setDeptNo(11).setDname("sss").setDb_source("001")
*/
}
3 【子模块:服务提供者 springcloud-provider-dept-8001】搭建
新建子模块(空 Maven),名为 springcloud-provider-dept-8001,因为微服务架构中,模块项目会越来越多,所以将项目的端口号加在项目名后面也是个较好的习惯。
最终结构如下图:
引入所需依赖,pom 文件内容如下:
<?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>mysrpingcloud</artifactId>
<groupId>com.zlc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-provider-dept-8001</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<!--我们要拿到实体类,需要配置 api module-->
<dependency>
<groupId>com.zlc</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--jetty-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<!--热部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
项目基本配置,application.yml 文件内容如下:
server:
port: 8001
mybatis:
type-aliases-package: com.zlc.springcloud.pojo
mapper-locations: classpath:mybatis/mapper/*Mapper.xml
config-location: classpath:mybatis/mybatis-config.xml
spring:
application:
name: springcloud-provider-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/db01?useUnicode=true&characterEncoding=utf-8
username: root
password: 123456
Mapper层:DeptDao、DeptMapper.xml
Service层:DeptService、DeptServiceImpl
如下:
Controller层:DeptController
如下:
编写启动类,进行测试
访问成功
4 【子模块:服务消费者 springcloud-consumer-dept-8002】搭建
新建一个名为 springcloud-consumer-dept-8002 的子模块(空 Maven)。
最终,此模块的结构如下:
引入相关依赖,pom 文件内容如下:
<?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>mysrpingcloud</artifactId>
<groupId>com.zlc</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-consumer-dept-8002</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<!--实体类+web-->
<dependencies>
<dependency>
<groupId>com.zlc</groupId>
<artifactId>springcloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>
配置此模块的端口信息,application.yml 内容如下:
当我们从服务消费端去调用服务提供者的服务的时候,使用了一个提供许多访问远程 http 服务的方法,简单的 Restful 服务模板的对象,这个类叫做 RestTemplate,因此,在此 SpringBoot 项目中,我们要先把这个类的一个实例注册到 Spring 容器中,方法如下(这也是 @Bean 注解的与 @Component 注解相比,后者所比拟不了的注册 Bean 的方式,即不必侵入源码,返回对象直接注册到 Spring 容器中):
服务消费者的控制层如下(服务消费者模块只有控制层,不需要有业务层),通过 RestTemplate 的 postForObject 或 getForObject 方法,并传入参数,如 url 地址、参数实体类、返回值的类型,因此,这三项(当然get~ 是两项),也是我们需要在使用这个远程模块的服务前需要知道和明确的。
最后,我们编写一个 SpringBoot 的启动类来测试
5 服务调用测试
启动这两个子模块,一个是服务提供者,一个是服务消费者:
首先我们直接访问服务提供者的服务:
接下来我们让消费者去使用服务提供者的服务,
测试成功:
再测试一个消费者中调用提供者的服务,
测试成功: