如何用Eureka + Feign搭建分布式微服务

 更新时间:2021年06月19日 14:39:05   作者:maojunhat  
Eureka是Spring Cloud Netflix的一部分,是一个服务注册中心。其服务生态中主要有三个角色:Eureka注册中心、服务提供者、服务消费者。服务提供者注册到Eureka后,服务消费者就能够直接向Eureka查询当前有哪些服务可用,再从中选取一个消费.本文讲解如何搭建分布式微服务

Eureka

Eureka主要解决了消费者对服务的记忆问题。如果没有Eureka,那么消费者必须记忆每个服务的地址,且一旦服务提供者宕机或地址发生变更,很可能不会收到通知,导致地址失效。加入Eureka后,只需记住Eureka注册中心的地址就能够找到其它所有服务。

此外,Eureka能够接受多个服务的注册,还能够通过其它组件的加持直接替代消费者进行负载均衡,使消费者无需手动选择服务。

Feign

Feign是一个模板化的HTTP客户端。通过Feign,可以做到像调用一个本地方法一样请求远程服务,无需编写繁杂的代码来创建HTTP请求。

创建父项目

项目主要分为三个微服务:服务提供者、服务消费者、Eureka注册中心。为了方便演示,三个项目都在同一个主机上运行,且都放在一个父项目里。

首先在IDEA中创建一个空项目,然后分别在项目中新建对应的三个Spring模块:

  • EurekaServer: 注册中心,依赖为Eureka Server。
  • ServiceProvider: 服务提供者,依赖为Eureka Discovery Client, Spring Web。
  • ServiceConsumer: 服务消费者,依赖为OpenFeign, Eureka Discovery Client, Spring Web。

注册中心

服务提供者通过向注册中心注册,提供它们的地址供调用;服务消费者向注册中心请求来获取可用的服务。

主要依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

配置文件

# 端口
server.port=1000
# 指定应用名称
spring.application.name=server
# 是否拉取其它服务器的注册信息
eureka.client.fetch-registry=false
# 是否向其它服务器注册
eureka.client.register-with-eureka=false
# 指定服务url
eureka.client.service-url.defaultZone=http://localhost:1000/eureka

默认情况下,Eureka服务器假定自己是集群的一部分,会定期向其它Eureka服务器注册自己,并获取其它服务器的注册信息。由于本项目仅部署一个Eureka服务器提供注册服务,所以不需要这两个动作,通过配置文件的eureka.client.fetch-registry和eureka.client.register-with-eureka两个属性禁用。

eureka.client.service-url包含了每个zone的名称和地址。defaultZone是一个特殊的key,如果客户端没有指定所需的zone,就会使用这个默认的zone。一般情况下defaultZone的地址就是Eureka服务器本身。

主类

@SpringBootApplication
@EnableEurekaServer
public class MyEurekaServerApplication {

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

要启动Eureka注册服务,在原生的Spring Boot启动类上注解@EnableEurekaServer即可。

项目启动后,访问localhost:1000就能看到Eureka提供的界面了。如果在界面上看到警告

EMERGENCY! EUREKA MAY BE INCORRECTLY CLAIMING INSTANCES ARE UP WHEN THEY'RE NOT. RENEWALS ARE LESSER THAN THRESHOLD AND HENCE THE INSTANCES ARE NOT BEING EXPIRED JUST TO BE SAFE.

是正常现象。Eureka服务器默认开启了自我保护模式。由于没有收到集群中大部分服务器的心跳(本项目中就一个Eureka服务器,所以该服务器不会收到任何心跳,自我保护模式也没有多少影响),Eureka假定出现了网络问题,开启自我保护模式。在自我保护模式下,已经注册的服务不会因为没有收到心跳而被注销。

如果要关闭自我保护,可以在配置中设置如下属性。

eureka.server.enable-self-preservation=false

服务提供者

服务提供者将自己注册到注册中心。

主要依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

spring-cloud-starter-netflix-eureka-client依赖包含了Eureka客户端(即服务提供者)的实现;spring-boot-starter-web用于将服务暴露为HTTP端点。

配置文件

# 应用端口
server.port=2000
# 应用名称
spring.application.name=service
# 注册中心地址
eureka.client.service-url.defaultZone=http://localhost:1000/eureka

eureka.client.service-url.defaultZone属性告诉Eureka客户端从哪里找到注册中心。

主类及Controller

@SpringBootApplication
public class MyEurekaServiceApplication {

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

}

@RestController
@RequestMapping("/test")
@Slf4j
class MyController {
    @Value("${server.port}")
    private int serverPort;

    @GetMapping
    public String getHandler() {
        log.info("##############received call, port: " + this.serverPort);
        return "test msg";
    }
}

为了展示方便,这些类都写在同一个文件中,下同。

这里的Controller提供了一个简单的服务:只要访问/test路径,就返回一个字符串test msg。如果有需要,可以同时启动多个服务实例,模拟服务器集群提供服务的情况。

@Slf4j是lombok提供的辅助注解,用于在类中方便地声明一个Logger实例log。

@Value是Spring提供的注解,用于获取配置文件中的信息。本例中就获取了之前配置的属性server.port=2000的值2000,注入到域serverPort中。

启动服务提供者后,会自动向配置文件中指定的Eureka服务器进行注册。此时访问之前的Eureka服务器界面,能够看到已经注册的服务信息。这里我分别修改端口号启动了3个实例。

此时访问服务提供者所在端口的/test路径就能够收到服务提供的字符串。

客户端

Feign是一个模板化的HTTP客户端。通过Feign,可以做到像调用一个本地方法一样请求远程服务,无需编写繁杂的代码来创建HTTP请求。

客户端通过Feign的加持,可以方便地发出请求,也可以加入Hystrix的负载均衡、熔断降级等功能。

主要依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

配置文件

# 应用端口
server.port=3000
# 应用名称
spring.application.name=feignClient
# 注册中心地址
eureka.client.service-url.defaultZone=http://localhost:1000/eureka

同上,eureka.client.service-url.defaultZone属性指定了客户端应该到哪个地址寻找注册中心。

主类、Controller及Feign映射

@FeignClient(value = "service")
interface FeignController {
    @GetMapping("/test")
    public String getHandler();
}

@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
public class MyFeignClientApplication {

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

}

@RestController
@RequestMapping("/test")
class MyRestController {
    @Autowired
    FeignController feignController;

    @GetMapping
    public String getHandler() {
        return feignController.getHandler();
    }
}

类中的接口FeignController将发往该端口的HTTP请求映射为向服务的请求。本例中,@FeignClient(value = "service")指定了将调用映射为向service服务的请求。而用@GetMapping("/test")则代表每当调用该方法,就向/test路径请求。综上,每当调用该方法,该服务就会向名为service的服务的/test路径发送HTTP GET请求。这就是Feign的方便之处。

在启动类上需要注解@EnableFeignClients和@EnableDiscoveryClient,启动对Feign接口的扫描和对Eureka服务器的发现。

类中还写了一个MyRestController,用于将对该服务的请求映射到方法调用。调用链为:

  • 浏览器向Controller发送HTTP请求
  • Controller收到请求后调用Feign接口中的方法
  • Feign将对方法的调用映射为对注册中心中服务的请求并返回

这样一来,用户体验到的过程就是:通过Feign发送了一个请求,然后收到了远程服务器上的信息。

启动客户端,访问客户端所在端口的/test路径,正确收到了服务提供的字符串。

相关文章

  • Java中ArrayList和SubList的坑面试题

    Java中ArrayList和SubList的坑面试题

    集合是Java开发日常开发中经常会使用到的,下面这篇文章主要给大家介绍了关于Java中ArrayList和SubList的坑面试题,需要的朋友可以参考下
    2022-05-05
  • java中获取当前服务器的Ip地址的方法

    java中获取当前服务器的Ip地址的方法

    本篇文章主要介绍了java中获取当前服务器的Ip地址的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • JAVA后台转换成树结构数据返回给前端的实现方法

    JAVA后台转换成树结构数据返回给前端的实现方法

    这篇文章主要介绍了JAVA后台转换成树结构数据返回给前端的实现方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • maven 在执行package,install,deploy时使用clean与不使用clean的不同之处

    maven 在执行package,install,deploy时使用clean与不使用clean的不同之处

    有时候用mvn install后,新改的内容不生效,一定要后来使用mvn clean install 才生效,由于之前没有做记录,以及记不清是什么情况下才会出现的问题,于是想看看clean和不clean的区别,感兴趣的朋友跟随小编一起看看吧
    2021-08-08
  • SpringBoot log打印及输出方式

    SpringBoot log打印及输出方式

    这篇文章主要介绍了SpringBoot log打印及输出方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java中的Optional类详细解读

    Java中的Optional类详细解读

    这篇文章主要介绍了Java中的Optional类详细解读,Optional是Java中的一个类,它的作用是用于解决空指针异常的问题,它提供了一些有用的方法,可以帮助我们避免显式进行空值检测,需要的朋友可以参考下
    2023-08-08
  • Java将List转换为String的几种方式

    Java将List转换为String的几种方式

    我们大家在实际开发中经常遇到List转为String字符串的情况,下面这篇文章主要给大家介绍了关于Java将List转换为String的几种方式,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-05-05
  • 二代身份证验证示例

    二代身份证验证示例

    这篇文章主要介绍了二代身份证验证示例,需要的朋友可以参考下
    2014-02-02
  • Java发送邮箱验证码、session校验功能

    Java发送邮箱验证码、session校验功能

    本篇主要描述“发送邮箱验证码、session校验”相关前(html\js)后(java)台代码,业务逻辑示例,需要的朋友可以参考下
    2018-02-02
  • 深入理解SpringBoot中关于Mybatis使用方法

    深入理解SpringBoot中关于Mybatis使用方法

    这篇文章主要介绍了SpringBoot中关于Mybatis使用方法,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
    2018-03-03

最新评论