服务注册、发现和远程调用

码农UP2U

共 5467字,需浏览 11分钟

 ·

2021-10-11 17:35

早期文章


        本篇文章介绍如何完成一个简单的服务注册、发现和远程调用的 Demo,通过该 Demo 来学习和了解关于 Spring Cloud 相关的知识。


项目结构

        创建一个 Maven 的聚合项目,使用 SpringBoot 作为其父项目,然后通过在其下添加子模块来构建一个简单的微服务的项目。


创建一个 service_user 服务

        在 Maven 项目下创建一个 Module 作为子模块,在项目的 POM 文件中加入 web 依赖,依赖如下:

<dependency>    <groupId>org.springframework.bootgroupId>    <artifactId>spring-boot-starter-webartifactId>dependency>

        引入依赖后,创建 controller、service、impl 三个包,然后分别创建 UserController、UserService 和 UserServiceImpl 三个类文件,以及一个启动类。项目结构如下图。

        该项目来模拟通过输入用户的 id 来返回用户名。UserController 代码如下:

@RestController@RequestMapping("/admin/user")public class UserController{    @Autowired    private UserService userService;
@GetMapping("getUser/{id}") public String getUser(@PathVariable Long id) { return userService.getUser(id); }}

        UserServiceImpl 的代码如下:

@Servicepublic class UserServiceImpl implements UserService{
@Override public String getUser(Long id) {
        String name = null;                if (id == 1) { name = "admin"; } else { name = "user"; }
return name; }}

        application.yml 配置文件如下:

server:  port: 8001spring:  application:    name: service-user

        注意,这里的 spring.application.name 的名字不能使用 下划线,否则后面使用 OpenFeign 进行远程调用时会报错。

        因为创建的子模块是 Maven 类型的项目,因此需要手动添加启动类,代码如下:

@SpringBootApplicationpublic class ServiceUserApplication{    public static void main(String[] args)    {        SpringApplication.run(ServiceUserApplication.class, args);    }}

        启动项目,访问 8001 端口来请求我们的接口,如下所示。


创建 service_dict 项目

        接着再创建一个子模块,同样引入 web 依赖,创建 controller、service 和 impl 的包,并创建 DictController、DictService 和 DictImpl 三个类,以及启动类和 application.yml 配置文件,项目结构如下:

        分别来写 DictController 和 DictServiceImpl 两个类的代码,DictController 代码如下:

@RestController@RequestMapping("/admin/dict")public class DictController{    @Autowired    private DictService dictService;
@GetMapping("getDict/{id}") public String getDict(@PathVariable Long id) { return dictService.getDict(id); }}

        DictServiceImpl 代码如下:

@Servicepublic class DictServiceImpl implements DictService{
@Override public String getDict(Long id) {
String name = null;
if (id == 1) { name = "管理员"; } else { name = "普通用户"; }
return name; }}

        application.yml 配置文件如下:

server:  port: 8002spring:  application:    name: service-dict

        该项目的端口号为 8002,在添加了该项目的启动类之后,启动该项目,访问 8002 接口,如下图所示。


服务注册

        可以看到,我们完成了两个服务,第一个服务通过 id 来获取用户名,第二个服务通过 id 来判断用户的类型。为了提高服务的可用性,可以将每个服务进行水平扩展,当调用这些服务的时候,服务有不同的 IP 地址,或者有不同的端口号。想要调用服务,就需要知道服务的 IP 地址和端口号。但是,这样做有一定的问题,比如某个服务下线了,或者新增加了服务,那么调用方需要动态的了解服务的变化,而服务的地址直接在调用方里进行管理,那么就不方便了。

        在这种情况下,可以通过服务注册中心来动态的管理服务,服务中心有 Zookeeper、Eureka、Nacos 等。这里我们使用 Nacos 来管理服务的注册。这里,我们在 Windows 下启动 Nacos,启动画面如下:

        然后通过浏览器访问 http://localhost:8848/nacos 来访问 Nacos 的管理页面,登录后的管理页面如下图所示:

        有了 Nacos 后我们修改上面的两个子模块,让两个子模块将自己注册到 Nacos 中。分别在 service_user 和 service_dict 的 POM 文件中增加如下的依赖。

<dependency>    <groupId>com.alibaba.cloudgroupId>    <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>    <version>2.2.6.RELEASEversion>dependency>

        并在启动类上增加注解,注解如下:

@EnableDiscoveryClient

        在 application.yml 中将注册中心的地址配置一下,配置如下:

server:  port: 8002spring:  application:    name: service-dict  cloud:    nacos:      discovery:        server-addr: 127.0.0.1:8848

        然后重新启动这两个子模块,这样,两个服务就被注册到了 Nacos 中,可以在 Nacos 中查看服务列表,如下图所示。

        通过上图可以看到,已经将自己注册到了 Nacos 中。


服务发现与远程服务调用

        现在,我们让 service_user 去调用 service_dict 来模拟一次远程调用的过程,也就是在调用 getUser 接口时,在 getUser 接口的内部去调用 getDict 接口。

        创建一个子模块,命名为 client,引入如下依赖:

<dependency>    <groupId>org.springframework.cloudgroupId>    <artifactId>spring-cloud-starter-openfeignartifactId>    <version>2.2.9.RELEASEversion>dependency>

        有了该依赖以后,在项目中添加一个接口,通过该接口调用 service_dict 下的 getDict 接口。项目结构如下:

        这里只有 DictFeignClient 接口文件,该文件的代码如下:

@FeignClient("service-dict")@Repositorypublic interface DictFeignClient{    @GetMapping("/admin/dict/getDict/{id}")    String getDict(@PathVariable Long id);}

        在注解 @FeignClient 中定义服务的名称,在 @GetMapping 注解中写入接口地址的 uri将该子模块引入 service_user 中,即可通过 OpenFeign 来完成远程调用。修改 service_user 中的 UserServiceImpl 文件,代码如下:

@Servicepublic class UserServiceImpl implements UserService{
@Autowired private DictFeignClient dictFeignClient;
@Override public String getUser(Long id) {
String name = null;
String dictName = dictFeignClient.getDict(id);
if (id == 1) { name = "admin"; } else { name = "user"; }
return name + " " + dictName; }}

        使用 @Autowired 来注入 DictFeignClient,调用 DictFeignClient 接口中定义的 getDict 来调用 service_dict 中的 getDict 接口。这样就完成了远程调用。在 service_user 的启动类上加如下注解:

@EnableFeignClients(basePackages = "com.coderup2u")

        重新启动 service_user 项目,并在浏览器中进行访问 getUser 接口,如下图所示。

        从上面的代码中可以看出,进行远程调用时,只定义了服务的名称,也就是 通过 @FeignClient("service-dict"),但是并没有给出该服务实际的地址和端口号。由此,我们可以想到,服务的 IP 地址和端口号是由服务中心获取到的,即服务发现。服务发现会动态的根据注册中心服务列表的变化而变化。当服务增加、下线,注册中心管理的地址列表都会发生变化,从而提供给服务调用方,这样就避免了调用了已经下线的服务,从而导致服务调用的失败。他们大致的关系如下图所示。



总结

        本文通过简单的 Demo 介绍 Spring Cloud Alibaba 中 Nacos 的使用,服务注册、服务发现,及远程服务的调用。可以通过在简单的 Demo 上来完成 Nacos 集群的搭建,服务集群的搭建来进行测试。



公众号内回复 【mongo】 下载 SpringBoot 整合操作 MongoDB 的文档。


更多文章


浏览 59
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报