2021SC@SDUSC
一、概述
在老年健康管理系统的后端代码中,使用了当前火热的微服务技术。微服务架构改变了传统单体架构的模式,使不同功能,不同模块之间的代码更加解耦合。微服务将服务进行原子化拆分,不同为服务之间独立打包,部署和升级,运维成本也大大降低。在本次项目中,微服务之间的通信使用使用了Http请求(Restful方式),使不同微服务之间能互相传递信息。当系统中一个服务需要调用另一个服务提供的接口时,可以向另一个服务发送Http请求,获取另一个服务提供的服务。
经过小组讨论,决定由我负责微服务部分代码的阅读和理解,本篇博客主要围绕老年健康管理系统后端微服务环境的整体架构,注册中心,配置中心和服务间通信等进行代码分析。
二、核心代码
在本项目后台的微服务构建中,有几个比较重要的基础部分。第一个部分是微服务搭建的部分,第二部分是每个服务的注册和服务间通信,第三个部分是微服务之间互相通信的负载均衡问题。接下来我将从这三个方面介绍本项目的内容。
2.1 微服务搭建
在老年健康管理系统中,后端使用目前行业中通用的Spring Cloud框架完成微服务的治理任务。处理使用Spring Cloud框架以外,还是用了Spring Cloud Alibaba的Nacos组件作为注册和配置中心
由于后端使用了Spring Cloud作为微服务治理的框架,因此本项目的pom.xml的形式与一般单体应用的pom.xml略有区别
在父项目中继承了Spring Boot项目
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<relativePath/>
</parent>
使用dependencyManagement标签维护父项目的总依赖
这部分依赖是用于整个父项目,父项目中的具体子项目(所有微服务),都会继承该父项目的全部依赖。这样的方便之处在于,微服务不需要再关注具体的版本号,只需要引入微服务对应的父项目的依赖即可(类似上面父项目引入Spring Boot依赖那样)
<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok-version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<version>${devTool-version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
版本号的维护
随着服务的不断增加,需要的依赖也越来越多,本项目中利用properties标签对版本号进行公共维护,便于修改,在这里可以看到,Spring Cloud的版本是Hoxton.SR8,早期Spring Cloud的版本号是以伦敦地铁站的站名命名的。
<properties>
<spring.cloud-version>Hoxton.SR8</spring.cloud-version>
<lombok-version>1.18.20</lombok-version>
<devTool-version>2.5.3</devTool-version>
</properties>
2.2 注册和配置中心
2.2.1 服务注册中心
在微服务系统中,由于微服务众多,且不同微服务往往以集群形式部署,因此需要一个统一注册管理中心用于管理所有的微服务,查看微服务的健康状况,等等。在本项目中,使用Spring Cloud Alibaba的Nacos作为服务注册中心。
为了使用Nacos组件,本项目在pom.xml中引入了Nacos依赖
首先在父项目中引入Spring Cloud Alibaba
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring.cloud.alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
对应的版本号为
<properties>
<spring.cloud.alibaba.version>2.2.1.RELEASE</spring.cloud.alibaba.version>
</properties>
接着在子项目中引入nacos依赖
注意,子项目中的依赖并没有版本号,只有groupId和artifactId,这是因为在父项目中已经指定了相应依赖的版本,因此子项目中不需要重复指定。
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
</dependencies>
主程序
通过阅读源码可知,注册到nacos注册中心的客户端类的启动类就是一个简单的Spring Boot启动类,与其他的项目类似
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class UserApplication
{
public static void main(String[] args) {
SpringApplication.run(NacosClientApplication.class, args);
}
}
通过查阅资料,我了解到,Nacos可以认为是一个小的软件(该软件的作用是用于服务注册),默认占用服务器的8848端口,使用Nacos的好处在于,不需要再在微服务中单独定义一个工程,这个工程仅用于充当服务注册中心(类似Eruka)。使用Spring Boot集成Nacos后,仅需要引入依赖,并在bootstrap.properties中配置Nacos的基本信息,即可在启动时自动注册到Nacos。
配置信息如下
spring.cloud.nacos.config.server-addr=localhost:8848
Nacos服务注册中心默认以集群的方式启动。
2.2.2 配置中心
在微服务的治理过程中,由于每个微服务都有自己的配置文件,而微服务通常以集群的方式部署,如果所有的配置文件都放在本地,那么修改起来将会非常麻烦,需要对微服务集群中的每一个节点都进行修改,这显然是不合理的。因此在阅读源码的过程中,我发现该系统将所有的配置文件,都放到nacos的配置中心中,将配置中心放到一个集中的云配置中心中,便于更改。此外,nacos在管理配置文件的过程中,还会对配置文件进行版本控制。
bootstrap.properties配置
在使用统一注册中心后,本项目将原本的application.properties变为bootstrap.properties,这样才能拉取到远端的具体配置。
#nacos配置中心ip和端口
spring.cloud.nacos.config.server-addr=localhost:8848
#组名
spring.cloud.nacos.config.group-name=NURSE_GROUP
#配置文件名
spring.cloud.nacos.config.name=nurse-prod
#配置文件后缀
spring.cloud.nacos.config.file-extension=properties
尽管使用了统一的配置中心,但在本地的bootstrap.properties依然要书写少量的配置信息,这部分配置信息的主要作用是告诉该服务配置文件具体的位置。
2.3 服务间通信
在老年健康管理系统中,不同微服务之间的通信有多种方式。本篇博客不对MQ(异步消息队列)通信方式做过多介绍,仅对普通的Http通信进行介绍。(后续会对MQ消息通信部分得源码进行阅读并介绍)
使用RestTemplate进行通信
在本项目中,有少部分代码使用RestTemplate进行通信,RestTemplate是一个类,可以发送Http请求,另外,在使用RestTemplate的同时,还是用了Ribbon组件使服务间的通信负载均衡。在阅读源码的过程中,我发现他对RestTemplate进行了封装配置,已保证负载均衡的效果。
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class BeansConfig
{
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
通过阅读源码可知,本项目使用自动注入的方式注入前面配置好的RestTemplate对象
@Autowired
private RestTemplate restTemplate;
使用OpenFeign进行服务间通信
在本项目中,处理上面的通信方式以外,还使用了Spring Cloud的Open Feign组件进行不同服务间的通信,使用Open Feign进行通信比前面的RestTemplate通信的优点在于,不会将路径写死,且在使用OpenFeign进行通信的过程中会自动实现请求的负载均衡,不需要再使用@loadBalance注解。
通过阅读源码可知,在使用Open Feign时,首先引入了OpenFeign的相关依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
这里以一个简单的例子展示项目中OpenFeign配置类的具体配置
import org.springframework.cloud.openfeign.FeignClient;
@FeignClient("user")
public interface UserClient
{
@GetMapping("user")
String getCurrentUser(@RequestParam("name") String name,@RequestParam("age") Integer age);
}
在对应的controller类中,自动注入该接口对象,而后调用对应的方法,即可直接发送请求
@Autowired
private UserClient userClient;
三、总结
在本篇博客中,我主要对项目中微服务治理的部分源代码进行了解读,通过对这部分源代码的解读,我对微服务之间的关系理解得更深刻了。此外,由于本项目在微服务治理的源代码内容较多,一篇博客难以分析完,在后面的博客中我也会对这一部分源码进行更进一步地分析。
最后感谢老师和小组成员对我提供的帮助,这让我更好地在阅读源码的过程中学习到更多地知识了。
|