SpringCloud 微服务架构系列 -- 服务的注册、发现与调用

本贴最后更新于 1896 天前,其中的信息可能已经时移俗易

简介

众所周知,SpringCloud 是一个微服务框架,本质上是基于 SpringBoot 的一整套实现微服务的框架。包含了服务发现、负载均衡、断路器、服务网关、分布式配置等组件。其中服务注册、发现又有 Netflix 的 Eureka,阿里的 Dubbo,Apache 的 Consul 等,本篇文章将以 Eureka 进行讲解。

Eureka

Eureka 是 Netflix 开发的服务发现框架,本身是一个基于 REST 的服务。由两个组件组成:

  • Eureka Server:也被称作是服务注册中心,用于提供服务的注册与发现。
  • Eureka Client:包含服务消费者与服务生产者。

image.png
图片来源于互联网,如侵权可联系博主

Eureka 的作用就是将我们定义的 API 接口注册到 Eureka 服务器上,方便管理,调用的时候只需要知道服务名就可以,不再通过 IP 加端口号的方式调用,利于解耦。

服务的注册与发现

一、新建主项目

  1. 选择 Maven,点击 Next
    image.png
  2. 填写相关信息,点击 Next
    image.png
  3. 确定信息无误后,点击 Finish
    image.png
  4. src 文件夹删除(如果有的话)打开 pom.xml 文件,添加如下代码。
        <!--必须指定该父模块,不然后面子模块启动会报错,很麻烦-->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.7.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
    
        <!--父模块类型必须为pom-->
        <packaging>pom</packaging>
    
        <!--包含子模块-->
        <modules>
    
        </modules>
    
        <!--在父模块添加web依赖,子模块可继承该依赖-->
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
        </dependencies>
    

二、新建 Eureka Server

  1. 在项目上右键新建 Module
    image.png
  2. 选择 Spring Initializr,点击 Next,填写相关信息,Next
    image.png
  3. 选择导入 Eureka Server 依赖,Next,确认信息,点击 Finish
    image.png
  4. 打开 Server 模块的 pom.xml 文件,修改 <parent> 标签
        <parent>
            <groupId>org.sakura</groupId>
            <artifactId>eureka</artifactId>
            <version>1.0-SNAPSHOT</version>
        </parent>
    
  5. 打开主模块的 pom.xml 文件,在 <modules> 标签添加相应的子模块
        <!--包含子模块-->
        <modules>
            <module>Server</module>
        </modules>
    
  6. 将 Server 模块中的 application.properties 重命名为 application.yml,并添加如下信息,也可直接使用 properties 文件类型(需修改如下代码)
    # Eureka 服务注册与发现的组件
    server:
      port: 8080
    
    spring:
      application:
        #服务名,很重要
        name: server
    
    eureka:
      instance:
        hostname: localhost
        #将prefer-ip-address设为开启时,将默认显示服务的地址,而非主机名
    #    prefer-ip-address: true  #以IP地址注册到服务中心,相互注册使用IP地址
    #    prefer-ip: 127.0.0.1   #显式设置服务的地址
    
      client:
        # 下面两个 false 表明自己是 server,而非 client
        register-with-eureka: false     # 不要使用 eureka 服务进行注册,即在管理界面不可见
        fetch-registry: false           # 不要在本地缓存注册表信息
        service-url:
          defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
    #      defaultZone: http://127.0.0.1:${server.port}/eureka/
    
      server:
        #开启自我保护模式
        enable-self-preservation: false
        #清理无效节点,默认60*1000毫秒,即60秒
        eviction-interval-timer-in-ms: 5000
    
  7. 修改 Server 模块的启动类,添加 @EnableEurekaServer 注解即可
    @EnableEurekaServer
    @SpringBootApplication
    public class ServerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ServerApplication.class, args);
        }
    
    }
    
  8. 启动 Server 服务,打开 http://localhost:8080
    image.png

三、新建 Eureka Client

  1. 新建 Client 模块,前两步和之前一样,只有导入依赖那里不一样
    image.png
  2. 修改子父模块的 pom.xml,与 Server 模块一样
  3. 修改 application.yml
    server:
      port: 8081
    
    spring:
      application:
        # 服务名,很重要
        name: client
    
    eureka:
      instance:
        hostname: localhost
       #以IP地址注册到服务中心,相互注册使用IP地址
    #    prefer-ip-address: true
    
      client:
        service-url:
          #服务注册地址
          defaultZone: http://${eureka.instance.hostname}:8080/eureka
    
    
    
  4. 修改启动类,添加 @EnableEurekaClient 注解(@EnableDiscoveryClient 或不加都可以)
    @EnableEurekaClient
    @SpringBootApplication
    public class Client1Application {
    
        public static void main(String[] args) {
            SpringApplication.run(Client1Application.class, args);
        }
    
    }
    
  5. 启动 Client 服务(启动 Client 前,需保证 Server 正在运行,不然会报错),打开刚才的链接
    image.png
    可以看到,Client 服务已经注册到服务中心了。这里可能有小伙伴会发现点击这个服务的链接是会出现 404 的,这是因为项目没有使用到 Actuator。

服务的调用

SpringCloud 有两种服务调用的方式

  • Ribbon
  • Feign

一、Ribbon

 SpringCloud Ribbon 是一个基于 HTTP 和 TCP 的客户端负载均衡工具,它基于 Netflix Ribbon 实现。几乎存在于每一个 SpringCloud 构建的微服务和基础设施中。因为微服务间的调用,API 网关的请求转发等内容,实际上都是通过 Ribbon 来实现的。

  1. 再创建一个 Client2 服务,配置文件中除端口与之前的 Client 不同外,其它都一致,服务名也一样,这是为了实现负载均衡。

    server:
      port: 8082
    
    spring:
      application:
        name: client
    
    eureka:
      instance:
        hostname: localhost
        #以IP地址注册到服务中心,相互注册使用IP地址
      #    prefer-ip-address: true
    
      client:
        service-url:
          #服务注册地址
          defaultZone: http://${eureka.instance.hostname}:8080/eureka
    
  2. 为两个 Client 各添加一个 API 接口

    @RestController
    public class HelloController {
    
        @GetMapping("/hello")
        public String sayHello(@RequestParam(required = true,name = "name") String name){
            return "Hello " + name + ", 8081";
        }
    }
    
    @RestController
    public class HelloController {
    
        @GetMapping("/hello")
        public String sayHello(@RequestParam(required = true,name = "name") String name){
            return "Hello " + name + ", 8082";
        }
    }
    
  3. 再新建一个 Robbon 模块,前面基本一样,依赖不同
    image.png

  4. 修改配置文件和 pom

    server:
      port: 8083
    
    spring:
      application:
        name: ribbon
    
    eureka:
      instance:
        hostname: localhost
        #以IP地址注册到服务中心,相互注册使用IP地址
      #    prefer-ip-address: true
    
      client:
        service-url:
          #服务注册地址
          defaultZone: http://${eureka.instance.hostname}:8080/eureka
    
  5. 修改启动类,需添加一个 RestTemplate bean

    @EnableDiscoveryClient
    @SpringBootApplication
    
    public class RibbonApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(RibbonApplication.class, args);
        }
    
        /**
         * 负载均衡配置
         * @return
         */
        @Bean
        @LoadBalanced
        RestTemplate restTemplate(){
            return new RestTemplate();
        }
    }
    
  6. 在 Ribbon 模块中加入一个 Service 和一个 Controller

    @Service
    public class HelloService {
    
        @Autowired
        RestTemplate restTemplate;
    
        public String helloService(String name){
            return restTemplate.getForObject("http://client/hello?name="+name,String.class);
        }
    }
    
    @RestController
    public class HelloController {
    
        @Autowired
        HelloService helloService;
    
        @GetMapping("/hello")
        public String hello(String name){
            return helloService.helloService(name);
        }
    }
    
  7. 依次启动 Server 模块和其它各模块
    image.png

    可以看到,两个 Client 和一个 Ribbon 都已经注册上去了

  8. 打开 http://localhost:8083/hello?name=sakura
    image.png
    每次刷新调用的服务都不同,证明客户端负载均衡成功了

二、Feign

Feign 是基于 Ribbon 实现的工具,采用基于接口的注解

  1. 新建 Feign 模块,引入依赖
    image.png

  2. 修改配置文件和 pom

    server:
      port: 8084
    
    spring:
      application:
        name: feign
    
    eureka:
      instance:
        hostname: localhost
        #以IP地址注册到服务中心,相互注册使用IP地址
      #    prefer-ip-address: true
    
      client:
        service-url:
          #服务注册地址
          defaultZone: http://${eureka.instance.hostname}:8080/eureka
    
  3. 修改启动类,添加 @EnableEurekaClient@EnableFeignClients

    @EnableFeignClients
    @EnableEurekaClient
    @SpringBootApplication
    public class FeignApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(FeignApplication.class, args);
        }
    
    }
    
  4. 创建一个 Service 接口

    @FeignClient(value = "client")  //value值为需要调用的服务名
    public interface IFeignService {
    
        @GetMapping("/hello")   //这里的地址为需要调用的服务里相应的接口地址
        String hello(@RequestParam(value = "name")String name);
    }
    
  5. 使用上面的接口(声明完上面 Feign 接口后,其他 Spring 管理的类,如 Service、Controller 都可以直接注入使用,IDEA 可能会提示不能注入,可忽略)

    @RestController
    public class HelloController {
    
        @Autowired
        private IFeignService iFeignService;
    
        @GetMapping("/feign/hello")
        public String sayHello(String name){
            return iFeignService.hello(name);
        }
    }
    
  6. 依次启动 Server 模块和 Feign 模块和 Client 模块
    image.png

  7. 访问 http://localhost:8084/feign/hello?name=sakura
    image.png

以上相对全面简洁的介绍了 SpringCloud 中服务的注册、发现与调用。代码已上传至 Github

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3186 引用 • 8212 回帖
  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    942 引用 • 1459 回帖 • 31 关注
  • 教程
    143 引用 • 597 回帖 • 8 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...