Spring Cloud第01讲:Eureka服务注册中心

文章仅作为本人学习笔记,有个人理解,也有参考及摘录各路大神的文章或者视频

1. 背景介绍

为什么会有服务注册中心这个东西出现,下面就来说一下。
原本的项目之间的调用如下:
项目A调用项目B
看着没什么要紧的,如果随着业务量的增加,系统也在增加,系统之间的调用可能就是下面酱紫的:
在这里插入图片描述
看着还凑合吧,如果系统有十几个甚至二三十个呢,全都是调用关系的连线,任何一个项目的修改都会导致其他相关联的好几个项目都跟着重启,很麻烦,而且容易出错。通过服务中心来获取服务你不需要关注你调用的项目IP地址,由几台服务器组成,每次直接去服务中心获取可以使用的服务去调用既可

如果使用服务注册中心的话,拿项目A调用项目B,项目B调用项目C来说,如下图:
服务注册中心后的项目之间调用
项目之间没有了直接调用。其实有点像企业服务总线的功能。公司内部可以使用服务注册中心,但是与外公司系统对接时,还是需要一个类似于服务注册中心的系统存在的,也就是企业服务总线。

2. Eureka简单介绍

Spring Cloud封装了Netflix公司开发的Eureka模块来是实现服务注册与发现。Eureka Server作为服务注册功能的服务器,是服务注册中心,而其他的微服务则使用Eureka的客户端连接到Eureka Server,并维持心跳连接。这样的话维护人员就可以通过Eureka Server来监控系统中各个微服务是否正常运行。

Eureka由两个组件组成Eureka服务器和Eureka客户端。Eureka服务器用作服务注册中心,Eureka客户端是一个java客户端。如下图:
eureka架构图上图描述了Eureka的基本架构,由3个角色构成,跟zookeeper是一样的。
1).Eureka Server

  • 提供服务的注册和发现

2).Service Provider

  • 服务提供者
  • 将自己的服务注册到Eureka,进而使服务消费者发现

3).Service Consumer

  • 服务消费者
  • 从Eureka Server订阅服务,获取注册服务列表

服务启动后向Eureka Server注册,Eureka Server会将注册信息向其他Eureka Server进行同步,当服务消费者要调用服务提供者,则向服务注册中心获取服务提供者地址(即:服务应用名,yaml配置文件中spring.application.name的值),然后会将服务提供者地址缓存在本地,下次再调用时,则直接从本地缓存中取,完成一次调用。

当服务注册中心Eureka Server检测到服务提供者因为宕机、网络原因不可用时,则在服务注册中心将服务置为DOWN状态,并把当前服务提供者状态向订阅者发布,订阅过的服务消费者更新本地缓存。

服务提供者在启动后,周期性(默认30秒)向Eureka Server发送心跳,以证明当前服务是可用状态。Eureka Server在一定的时间(默认90秒)未收到客户端的心跳,则认为服务宕机,注销该实例。

3. Eureka单点搭建

项目父工程统一管理版本添加如下依赖

<dependencyManagement>
	<dependencies>
		<!-- spring cloud -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<!-- (Spring cloud Finchley版本) -->
			<version>Finchley.RELEASE</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

3.1Eureka服务注册中心

3.1.1 pom添加依赖

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

3.1.2 启动类

启动类添加@EnableEurekaServer注解

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/*
 * @Author 友野浩二
 * @Description // eureka服务注册中心(Finchley版本), eureka-server
 * 启动项目后,在浏览器地址栏输入application.properties中配置的eureka.client.service-url地址,就可以查看eureka注册中心
 **/
@SpringBootApplication
@EnableEurekaServer
@Slf4j
public class JeresServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(JeresServerApplication.class, args);
        log.info("<<<<======== Tong Stand-Lone Eureka Server Started ========>>>>");
    }
}

3.1.3 配置文件

1).bootstrap.properties

# bootstrap.yml(bootstrap.properties):用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等
# bootstrap.yml 先于 application.yml 加载
# 应用名
spring.application.name=tong-jeres-server

2).application.properties

# application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=8000
# 实例主机名称
eureka.instance.hostname=127.0.0.1
# ==================================================
# 在默认情况下erureka server也是一个eureka client ,必须要指定一个 server。
# 通过eureka.client.registerWithEureka:false和fetchRegistry:false来表明自己是一个eureka server.
# 表示是否将自己注册到Eureka Server
eureka.client.register-with-eureka=false
# 表示是否从Eureka Server获取注册信息
eureka.client.fetch-registry=false
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 指定单台机器(集群多个地址可使用 , 分隔)
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:${server.port}/eureka/

3.1.4 验证

启动成功后,在浏览器地址栏输入http://127.0.0.1:8000可以看到如下图:
EurekaServer单点

3.2 Eureka服务调用者

3.2.1 pom添加依赖

<dependencies>
        <!-- eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- web服务基本依赖:内嵌了tomcat服务器,开发简单的web应用,此依赖即可 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
</dependencies>

3.2.2 启动类

启动类中添加@EnableDiscoveryClient@EnableDiscoveryClient(两者的区别见启动类的注释)

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @Author 友野浩二
 * @Description eureka服务提供者
 *
 * <pre>
 * 服务发现@EnableDiscoveryClient 和 @EnableEurekaClient的区别: 用法基本一致。
 *      spring cloud中discovery service有许多种实现(eureka、consul、zookeeper等)。
 *      @EnableDiscoveryClient 基于spring-cloud-commons;@EnableEurekaClient基于spring-cloud-netfix。
 *      简单说,如果选用的服务注册中心是eureka,那么就推荐@EnableEurekaClient,如果是其他注册中心,那么推荐使用@EnableDiscoveryClient。
 *      @EnableEurekaClient 的使用场景较为单一。
 * </pre>
 */
@SpringBootApplication
// 服务提供者启动类中添加@EnableDiscoveryClient或者@EnableEurekaClient注解,使用注解后,项目就具有了服务注册的功能。
//@EnableDiscoveryClient
@EnableEurekaClient
@Slf4j
public class JeresProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(JeresProviderApplication.class, args);
        log.info("<<<<======== Tong Stand-Lone Eureka Provider Started ========>>>>");
    }
}

3.2.3 配置文件

1).bootstrap.properties

# bootstrap.yml(bootstrap.properties):用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等
# bootstrap.yml 先于 application.yml 加载
# 应用名: 指定微服务的应用名,后续在调用的时候只需要使用该名称就可以进行服务的访问.
spring.application.name=tong-jeres-provider

2).application.properties

# application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=8001
# 实例主机名称
eureka.instance.hostname=127.0.0.1
# ==================================================
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 多个地址可使用 , 分隔
# 对应服务注册中心的配置内容,指定服务注册中心的位置。即eureka-server的配置内容。
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:8000/eureka/

3.2.4 Controller测试类

提供loveranswer服务

package cn.buddha.jeres.provider.controller;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author 友野浩二
 * @Description 服务提供者测试
 */
@RestController
@Slf4j
public class TongController {
    // http://127.0.0.1:8001/loveanswer?requestName=shihao
    @RequestMapping(method = RequestMethod.GET, value = "/loveanswer")
    public String loveAnswer(@RequestParam(value = "requestName") String requestName) {
        log.info("Do you love me ?");
        if ("shihao".equals(requestName)) {
            return "YES! I LOVE YOU!!!";
        }
        return "NO!";
    }
}

3.2.5 验证

1). 成功启动后,可以在服务注册中心类的日志中看到如下log日志

INFO 8672 --- [nio-8000-exec-3] c.n.e.registry.AbstractInstanceRegistry  : Registered instance TONG-JERES-PROVIDER/shihao:tong-jeres-provider:8001 with status UP (replication=false)

2). 在注册中心的页面也可以看到TONG-JERES-PROVIDER服务。
服务提供者单点3). 为了验证loveranswer这个restful服务是否好着呢,地址栏输入http://127.0.0.1:8001/loveranswer?requestName=shihao
服务提供者提供的服务loveranswer可以看到服务时好着的,防止后面服务消费者使用报错的时候太麻烦找错。

3.3 Eureka服务消费者(Feign调用)

3.3.1 pom添加依赖

<dependencies>
	<!-- eureka客户端 -->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
	</dependency>

	<!-- Spring Cloud Feign
         Feign是一个声明式Web Service客户端,使用Feign能让编写Web Service客户端更加简单。
         使用方法: 定义一个接口,然后在上面添加注解。同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。
         Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
	-->
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-openfeign</artifactId>
	</dependency>

	<!-- web服务基本依赖:内嵌了tomcat服务器,开发简单的web应用,此依赖即可 -->
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>
</dependencies>

3.3.2 启动类

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @Author 友野浩二
 * @Description 服务消费者
 * <pre>
 *    @EnableFeignClients : 启用feign进行远程调用
 *    Feign是一个声明式Web Service客户端,使用Feign能让编写Web Service客户端更加简单。
 *    使用方法: 定义一个接口,然后在上面添加注解。同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。
 *    Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
 * </pre>
 */
@SpringBootApplication
@EnableFeignClients
@Slf4j
public class JeresConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(JeresConsumerApplication.class, args);
        log.info("<<<<======== Tong Stand-Lone Eureka Consumer Started ========>>>>");
    }
}

3.3.3 配置文件

1).bootstrap.properties

# bootstrap.yml(bootstrap.properties):用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等
# bootstrap.yml 先于 application.yml 加载
# 应用名
spring.application.name=tong-jeres-consumer

2).application.properties

# application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=8002
# 实例主机名称
eureka.instance.hostname=127.0.0.1
# ==================================================
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 多个地址可使用 , 分隔
# 对应服务注册中心的配置内容,指定服务注册中心的位置。即eureka-server的配置内容。
eureka.client.service-url.defaultZone=http://${eureka.instance.hostname}:8000/eureka/

3.3.4 Feign调用

@FeignClient注解的 name属性:绑定的远程服务名(即服务提供者bootstrap.properties中配置的spring.application.name)

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @Author 友野浩二
 * @Description // feign调用实现
 * <pre>
 *      使用@FeignClient注解来指定这个接口所要调用的服务名称,接口中定义的各个函数使用 Spring MVC 的注解就可以来绑定服务提供方的 REST 接口。
 *      【注意】: 此类中的方法和远程服务中contoller中的方法名和参数需保持一致。
 * </pre>
 */
@FeignClient(name = "tong-jeres-provider")
public interface TongFeign {
    /*
     * 将远程服务http://tong-eureka-provider/loveanswer映射为一个本地Java方法调用。
     **/
    @RequestMapping(method = RequestMethod.GET, value = "/loveanswer")
    public String loveAnswer(@RequestParam(value = "requestName") String requestName);
}

3.3.5 Web调用远程服务

import cn.buddha.jeres.consumer.feign.TongFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author 友野浩二
 * @Description 服务消费者controller测试类
 */
@RestController
@Slf4j
public class ConsumerController {
    // 通过注解@Autowired使用定义feign的客户端
    @Autowired
    private TongFeign tongFeign;

    @RequestMapping(method = RequestMethod.GET, value = "/client")
    public String consumerHello(@RequestParam(name = "lover") String lover) {
        log.info("ConsumerController.consumerHello starting...");
        // 这里的使用本地Java API的方式调用远程的Restful接口
        String tongProvider = this.tongFeign.loveAnswer(lover);
        return "通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: ".concat(tongProvider);
    }
}

3.3.6 验证

浏览器地址栏输入http://127.0.0.1:8002/client?lover=shihao
可以看到响应结果,依然成功了。
服务消费者单点

4. Eureka集群搭建

原因:

服务消费者本地缓存了服务提供者的地址,即使Eureka Server宕机,也不会影响服务之间的调用,但是一旦新服务上线,已经在缓存在本地的服务提供者不可用了,服务消费者也无法知道,所以保证Eureka Server的高可用还是很有必要的。

在分布式系统中,任何的地方存在单点,整个体系就不是高可用的,Eureka 也一样,也要以集群的方式对外提供服务。【此处可以看一下zookeeper注册中心的paxos算法】

4.1 Eureka服务注册中心(3个节点)

4.1.1 pom添加依赖

同 3.1.1

4.1.2 启动类

同 3.1.2

4.1.3 配置文件

1).bootstrap.properties

spring.application.name=tong-jerec-server

2).application.properties

在Eureka Server集群时,需要部署多个节点,则需要同一个项目使用不同的配置。so,在本案例中使用JerecServerApplication一个项目通过不同的启动参数来启动占用不同端口的3个Server服务,来模拟Eureka集群。

包含以下3个文件:

  • application-server1.properties
  • application-server2.properties
  • application-server3.properties

A. application-server1.properties

# application.yml(application-server1.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=9001
# 2- eureka配置
# 实例主机名称
eureka.instance.hostname=eurekaServer1
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 指定集群机器(多个地址可使用 , 分隔),配置对方的地址作为Eureka Client进行相互注册
eureka.client.service-url.defaultZone=http://eurekaServer2:9002/eureka/,http://eurekaServer3:9003/eureka/
# 关闭自我保护机制
eureka.server.enable-self-preservation=false

B. application-server2.properties

# application.yml(application-server2.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=9002
# 2- eureka配置
# 实例主机名称
eureka.instance.hostname=eurekaServer2
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 指定集群机器(多个地址可使用 , 分隔),配置对方的地址作为Eureka Client进行相互注册
eureka.client.service-url.defaultZone=http://eurekaServer1:9001/eureka/,http://eurekaServer3:9003/eureka/
# 关闭自我保护机制
eureka.server.enable-self-preservation=false

C. application-server3.properties

# application.yml(application-server3.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=9003
# 2- eureka配置
# 实例主机名称
eureka.instance.hostname=eurekaServer3
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 指定集群机器(多个地址可使用 , 分隔),配置对方的地址作为Eureka Client进行相互注册
eureka.client.service-url.defaultZone=http://eurekaServer1:9001/eureka/,http://eurekaServer2:9002/eureka/
# 关闭自我保护机制
eureka.server.enable-self-preservation=false

可以看到server1、server2、server3三个文件中配置的端口号不同,hostname也不同(hostname需要在hosts文件中进行配置。Windows在C:\Windows\System32\drivers\etc\hosts,修改完后打开cmd输入ipconfig /flushdns才可以是其生效;Linux在/etc/hosts[需要root权限])。

4.1.4 启动项目

  1. 如何在idea中启动集群呢?
    在idea中点击“Edit Configurations”,弹出“Run/Debug Configurations”窗口。点“+”号,选择“Spring boot”。
    Run Configurations
    选择后填写如下,JerecServerApp1中Active profile配置的是server1(也就是application-server1.properties中的-后面的那个东东),JerecServerApp2配置的是server2:
    Run Configurations配置1
  2. 依次启动3个启动类
    在启动第1个和第2个的时候会发生打印如下错误,很正常,3个全部启动起来就好了,她就是在启动的时候就去找其他的server了而已:
com.sun.jersey.api.client.ClientHandlerException: org.apache.http.conn.ConnectTimeoutException: Connect to eurekaServer3:9003 timed out

正常启动后的日志如下:

Registered instance TONG-JEREC-SERVER/shihao:tong-jerec-server:9001 with status UP (replication=true)
Registered instance TONG-JEREC-SERVER/shihao:tong-jerec-server:9002 with status UP (replication=true)
Registered instance TONG-JEREC-SERVER/shihao:tong-jerec-server:9003 with status UP (replication=true)

可以看到注册成功了,我们再打开浏览器看一下 http://127.0.0.1:9001
eureka server1根据图可以看出server1的注册中心DS Replicas已经有了server2、server3的相关配置信息,并且出现在available-replicas中。

高可用性验证:
我们手动停止server3,过几分钟来观察,发现server3就会移动到unavailable-replicas一栏中,而且eureka上注册的实例已经没有了server3,表示server3不可用。
在这里插入图片描述

4.2 Eureka服务调用者(3个节点)

4.2.1 pom添加依赖

同3.2.1

4.2.2 启动类

桶3.2.2

4.2.3 配置文件

1).bootstrap.properties

# 应用名: 指定微服务的应用名,后续在调用的时候只需要使用该名称就可以进行服务的访问.
spring.application.name=tong-jerec-provider

2).application.properties

包含以下3个文件:

  • application-provider1.properties
  • application-provider2.properties
  • application-provider3.properties

A. application-provider1.properties

# application.yml(application-provider1.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=9011
# 实例主机名称
eureka.instance.hostname=127.0.0.1
# ==================================================
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 多个地址可使用 , 分隔
# 对应服务注册中心的配置内容,指定服务注册中心的位置。即eureka-server的配置内容。
eureka.client.service-url.defaultZone=http://eurekaServer1:9001/eureka/,http://eurekaServer2:9002/eureka/,http://eurekaServer3:9003/eureka/

B. application-provider2.properties

# application.yml(application-provider1.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=9012
# 实例主机名称
eureka.instance.hostname=127.0.0.1
# ==================================================
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 多个地址可使用 , 分隔
# 对应服务注册中心的配置内容,指定服务注册中心的位置。即eureka-server的配置内容。
eureka.client.service-url.defaultZone=http://eurekaServer1:9001/eureka/,http://eurekaServer2:9002/eureka/,http://eurekaServer3:9003/eureka/

C. application-provider3.properties

# application.yml(application-provider1.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=9013
# 实例主机名称
eureka.instance.hostname=127.0.0.1
# ==================================================
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 多个地址可使用 , 分隔
# 对应服务注册中心的配置内容,指定服务注册中心的位置。即eureka-server的配置内容。
eureka.client.service-url.defaultZone=http://eurekaServer1:9001/eureka/,http://eurekaServer2:9002/eureka/,http://eurekaServer3:9003/eureka/

4.2.4 controller测试类

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description 服务提供者测试
 */
@RestController
@Slf4j
public class ProviderController {
    // http://127.0.0.1:端口/loveanswer?requestName=shihao
    @RequestMapping(method = RequestMethod.GET, value = "/loveanswer")
    public String loveAnswer(@RequestParam(value = "requestName") String requestName, HttpServletRequest httpServletRequest) {
        log.info("I am a provider.");
        log.info("Do you love me ?");
        StringBuilder resultMsg = new StringBuilder(httpServletRequest.getRequestURL().toString());
        if ("shihao".equals(requestName)) {
            resultMsg.append(", YES! I LOVE YOU!!!");
        } else {
            resultMsg.append(", NO!");
        }
        return resultMsg.toString();
    }
}

4.2.5 验证

1). 成功启动后,可以在服务注册中心类的日志中看到如下log日志

Registered instance TONG-JEREC-PROVIDER/shihaod.digitalchina.com:tong-jerec-provider:9011 with status UP (replication=false)
Registered instance TONG-JEREC-PROVIDER/shihaod.digitalchina.com:tong-jerec-provider:9012 with status UP (replication=false)
Registered instance TONG-JEREC-PROVIDER/shihaod.digitalchina.com:tong-jerec-provider:9013 with status UP (replication=false)

2). 在注册中心的页面也可以看到TONG-JEREC-PROVIDER服务。
在这里插入图片描述3).为了验证loveranswer这个restful服务是否好着呢,地址栏输入http://127.0.0.1:9011/loveanswer?requestName=shihao
在这里插入图片描述

4.3 Eureka服务消费者

4.3.1 pom添加依赖

在3.3.1的基础上添加如下依赖

由于项目依赖的spring-boot-starter-parent的父工程是spring-boot-dependencies,在这个pom里面已经声明了httpclient的版本,所以在正式使用的时候不需要再写版本号

<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>${httpclient.version}</version>
	<exclusions>
		<exclusion>
			<artifactId>commons-logging</artifactId>
			<groupId>commons-logging</groupId>
		</exclusion>
	</exclusions>
</dependency>

4.3.2 启动类

同3.3.2

4.3.3 配置文件

1).bootstrap.properties

spring.application.name=tong-jerec-consumer

2).application.properties

# application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。
# 1- 端口号
server.port=9021
# 实例主机名称
eureka.instance.hostname=127.0.0.1
# ==================================================
# 设置与Eureka Server交互的地址,查询服务和注册服务都需要依赖这个地址。
# 默认地址org.springframework.cloud.netflix.eureka.EurekaClientConfigBean中有配置http://localhost:8761/eureka/
# 多个地址可使用 , 分隔
# 对应服务注册中心的配置内容,指定服务注册中心的位置。即eureka-server的配置内容。
eureka.client.service-url.defaultZone=http://eurekaServer1:9001/eureka/,http://eurekaServer2:9002/eureka/,http://eurekaServer3:9003/eureka/

4.3.4 Feign调用实现

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @Author 友野浩二
 * @Description // feign调用实现
 *
 * <pre>
 *     使用@FeignClient注解来指定这个接口所要调用的服务名称,接口中定义的各个函数使用 Spring MVC 的注解就可以来绑定服务提供方的 REST 接口
 *     name: 绑定的远程服务名(即,bootstrap.properties中配置的spring.application.name)
 *     【注意】: 此类中的方法和远程服务中contoller中的方法名和参数需保持一致。
 * </pre>
 **/
@FeignClient(name = FeignConstant.TONG_JERES_PROVIDER)
public interface JerecProviderFeign {

    /*
     * @Description // 将远程服务http://tong-eureka-provider/loveanswer映射为一个本地Java方法调用。
     **/
    @RequestMapping(method = RequestMethod.GET, value = "/loveanswer")
    public String loveAnswer(@RequestParam(value = "requestName") String requestName);
}

4.3.5 Web调用远程服务

import cn.buddha.jerec.consumer.feign.JerecProviderFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

/**
 * @Description 服务消费者controller测试类
 */
@RestController
@Slf4j
public class ConsumerController {
    @Autowired
    private JerecProviderFeign jerecProviderFeign;

    @RequestMapping(method = RequestMethod.GET, value = "/client")
    public String consumerHello() {
        log.info("ConsumerController.consumerHello starting...");
        // 这里的使用本地Java API的方式调用远程的Restful接口
        String tongProvider = this.jerecProviderFeign.loveAnswer("shihao");
        return "通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: ".concat(tongProvider);
    }
}

4.3.6 验证

eureka复制注册中心页面刷新一下,可以看到consumer也注册到注册中心了。
在这里插入图片描述浏览器输入http://127.0.0.1:9021/client,显示
在这里插入图片描述可以看出消费者调用到提供者集群的9013上了。
下面我们模拟发6次请求,看一下都发到服务提供者集群的那台机器了。

import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

/**
 * @Description http测试模拟请求
 */
@Slf4j
public class TestHttpClient {
    public static void main(String[] args) throws IOException {
        // 创建默认的httpclient
        CloseableHttpClient httpClient = HttpClients.createDefault();
        // 调用6次服务并输出结果
        for (int i = 0; i < 6; i++) {
            // 调用 GET 方法请求服务
            HttpGet httpget = new HttpGet("http://localhost:9021/client");
            // 获取响应
            HttpResponse response = httpClient.execute(httpget);
            // 根据 响应解析出字符串
            log.info(EntityUtils.toString(response.getEntity()));
        }
    }
}

运行日志如下:

INFO cn.buddha.jerec.consumer.TestHttpClient - 通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: http://127.0.0.1:9012/loveanswer, YES! I LOVE YOU!!!
INFO cn.buddha.jerec.consumer.TestHttpClient - 通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: http://127.0.0.1:9013/loveanswer, YES! I LOVE YOU!!!
INFO cn.buddha.jerec.consumer.TestHttpClient - 通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: http://127.0.0.1:9011/loveanswer, YES! I LOVE YOU!!!
INFO cn.buddha.jerec.consumer.TestHttpClient - 通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: http://127.0.0.1:9012/loveanswer, YES! I LOVE YOU!!!
INFO cn.buddha.jerec.consumer.TestHttpClient - 通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: http://127.0.0.1:9013/loveanswer, YES! I LOVE YOU!!!
INFO cn.buddha.jerec.consumer.TestHttpClient - 通过feign调用远程服务tong-eureka-provider的restful接口/loveanswer的结果: http://127.0.0.1:9011/loveanswer, YES! I LOVE YOU!!!

可以看出eureka server随机将请求发送给服务提供者了,这里可以看出eureka server起到了负载均衡的作用。

5. 参考文章

还没写完,太晚了,该睡觉了……

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值