SpringCloud(三)——客户端健康检测与常用配置

  1. 创建一个Eureka服务器,项目名称为ek-server,源代码如下

pom.xml 如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.zgy</groupId>
	<artifactId>ek-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>ek-server</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR5</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
复制代码

EkServerApplication.java 如下

package com.zgy.ekserver;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @EnableEurekaServer:说明该应用是一个Eureka服务器
 */
@SpringBootApplication
@EnableEurekaServer
public class EkServerApplication {

	public static void main(String[] args) {
		new SpringApplicationBuilder(EkServerApplication.class).web(true).run(args);
	}
}
复制代码

application.yml 如下

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
复制代码

测试Eureka是否启动成功

打开浏览器访问:http://localhost:8761/,出现下图则成功

  1. 创建一个服务提供者的项目,项目名称为ek-provider,源代码如下

pom.xml 如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.zgy</groupId>
	<artifactId>ek-provider</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>ek-provider</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

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

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>
复制代码

EkProviderApplication.java 如下

package com.zgy.ekprovider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @EnableEurekaClient:说明该应用是一个客户端
 */
@SpringBootApplication
@EnableEurekaClient
public class EkProviderApplication {

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

复制代码

Police.java 如下

package com.zgy.ekprovider;

public class Police {

    private Integer id;
    private String name;
    private String message;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

复制代码

PoliceController.java 如下

package com.zgy.ekprovider;

        import org.springframework.web.bind.annotation.GetMapping;
        import org.springframework.web.bind.annotation.PathVariable;
        import org.springframework.web.bind.annotation.RestController;

@RestController
public class PoliceController {

    @GetMapping("/call/{id}")
    public Police call(@PathVariable Integer id){
        Police police = new Police();
        police.setId(id);
        police.setName("张三");
        police.setMessage("AAA");

        return police;
    }
}

复制代码

测试服务提供者是否成功,访问http://localhost:8761/,出现下图即为成功

  1. 给服务提供者配置心跳检测

所谓的心跳检测,就是服务提供者会间隔一段时间不停的的向注册中心发送信息(这里称为心跳),意思是告诉注册中心我还在正常运行,请不要把我在你的注册列表中移除掉。

修改application.yml文件,如下

spring:
  application:
    name: ek-provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    lease-renewal-interval-in-seconds: 5 # 每隔5秒向注册中心发送一次心跳
logging:
  level:
    com.netflix: debug # 日志
复制代码

运行项目ek-server和ek-provider,测试心跳配置是否成功,在ek-provider的控制台如果打印了以下信息,则表示心跳配置成功

  1. 给服务提供者配置一个功能,让服务提供者告诉注册中心,如果我过了多少时间后没有向注册中心发送心跳请求,那么就把我从注册中心的列表中剔除掉

修改ek-provider的application.yml文件,如下

spring:
  application:
    name: ek-provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    lease-renewal-interval-in-seconds: 5 #每隔5秒向注册中心发送一次心跳,默认值为30
    lease-expiration-duration-in-seconds: 10 #告诉注册中心,如果我10秒都没有向你发送心跳请求,就把我从你的注册中心列表中剔除掉,默认值为90
logging:
  level:
    com.netflix: debug
复制代码

修改ek-server的application.yml文件,如下

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
  server:
    enable-self-preservation: false #关闭Eureka服务器的自我保护,默认为true
    eviction-interval-timer-in-ms: 5000 #Eureka服务器的清理注册列表功能,默认是60秒,这个配置就是让Eureka服务器多少时间清理一次注册列表
复制代码

运行项目ek-server和ek-provider,测试配置是否成功,访问http://localhost:8761/,如下图

然后停掉ek-provider项目,再访问http://localhost:8761/,如果出现下图,则配置生效

  1. 创建一个服务调用者的项目,醒目名称为ek-invoker,源代码如下

pom.xml 如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.zgy</groupId>
	<artifactId>ek-invoker</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>ek-invoker</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR5</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

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

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

复制代码

EkInvokerApplication.java 如下

package com.zgy.ekinvoker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class EkInvokerApplication {

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

复制代码

TestController.java 如下

package com.zgy.ekinvoker;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@Configuration
public class TestController {

    /*
    @LoadBalanced:该RestTemplate具有负载均衡的功能
     */
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    @GetMapping("/router")
    public String router(){
        RestTemplate restTemplate = getRestTemplate();
        String json = restTemplate.getForObject("http://ek-provider/call/100", String.class);
        return json;
    }
}

复制代码

application.yml 如下

server:
  port: 8081
spring:
  application:
    name: ek-invoker
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
复制代码
  1. 配置服务调用者,在多少秒后去注册中心获取注册列表数据

修改ek-invoker的application.yml文件,如下

server:
  port: 8081
spring:
  application:
    name: ek-invoker
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    registry-fetch-interval-seconds: 5 #多少秒去注册中心获取注册服务器列表数据,默认为30秒
logging:
  level:
    com.netflix: debug
复制代码

写个方法获取注册中心服务列表的数据,在TestController.java中,添加以下代码

package com.zgy.ekinvoker;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@Configuration
public class TestController {

    /*
    @LoadBalanced:该RestTemplate具有负载均衡的功能
     */
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    @GetMapping("/router")
    public String router(){
        RestTemplate restTemplate = getRestTemplate();
        String json = restTemplate.getForObject("http://first-police/call/100", String.class);
        return json;
    }

    /*
    获取注册中心服务列表数据
     */
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("/list")
    public String serviceCount(){
        List<String> services = discoveryClient.getServices();
        for(String service : services){
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
            System.out.println("serviceId:"+instances.size());
        }

        return "";
    }
}

复制代码

运行ek-server和ek-invoker,访问http://localhost:8081/list,出现下图则表示配置成功

ps:这里的serviceId为1,就是说注册中心的服务器列表有一条数据,我们看注册中心如图所示

红框所圈的就是注册中心的服务器列表的数据,而这条数据,其实就是服务调用者自己,因为服务调用者也注册到了注册中心的。

  1. 元数据的配置,就是把服务提供者所提供的一些数据,注册到注册中心去,让其他服务调用者(客户端),能够使用这些数据。

在ek-provider中的application.yml中添加如下代码

spring:
  application:
    name: ek-provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    #每隔5秒向注册中心发送一次心跳,默认值为30
    lease-renewal-interval-in-seconds: 5
    #告诉注册中心,如果我10秒都没有向你发送心跳请求,就把我从你的注册中心列表中剔除掉,默认值为90
    lease-expiration-duration-in-seconds: 10
    metadata-map:
      #配置了一个元数据,key为my-name,value为zgy
      my-name: zgy
logging:
  level:
    com.netflix: debug
复制代码

在ek-invoker项目中的TestController.java添加如下代码

package com.zgy.ekinvoker;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
@Configuration
public class TestController {

    /*
    @LoadBalanced:该RestTemplate具有负载均衡的功能
     */
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    @GetMapping("/router")
    public String router(){
        RestTemplate restTemplate = getRestTemplate();
        String json = restTemplate.getForObject("http://first-police/call/100", String.class);
        return json;
    }

    /*
    获取注册中心服务列表数据
     */
    @Autowired
    private DiscoveryClient discoveryClient;

    @GetMapping("list")
    public String serviceCount(){
        List<String> services = discoveryClient.getServices();
        for(String service : services){
            List<ServiceInstance> instances = discoveryClient.getInstances(service);
            System.out.println("serviceId:"+instances.size());
        }

        return "";
    }


    /*
    获取服务提供者所提供的元数据
    */
    @GetMapping("/meta")
    public String getMetaData(){
        List<ServiceInstance> instances = discoveryClient.getInstances("ek-provider");
        for(ServiceInstance instance : instances){
            String name = instance.getMetadata().get("my-name");
            System.out.println("name:"+name);
        }

        return "";
    }
}

复制代码

分别启动ek-server、ek-provider、ek-invoker项目,然后访问http://localhost:8081/meta,最后在ek-invoker项目的控制台显示如下信息,表示配置元数据成功

  1. 什么是自我保护模式

自我保护模式指的是当某些服务发送心跳的效率很低时,Eureka服务器就会将这些服务保护起来,但是不会将其在注册列表中剔除掉。

关闭Eureka服务器的自我保护模式,配置如下

eureka:
  server:
    enable-self-preservation: false #关闭Eureka服务器的自我保护,默认为true
复制代码
  1. 健康监控

为什么要引入健康监控,前面已经说过,服务提供者会每隔一段时间向注册中心发送心跳,表明自己还在正常运行,请不要将我从注册中心的注册列表中剔除掉,但是,在实际开发环境中,服务提供者会出现每隔一段时间正常的向注册中心发送心跳,但是其实这个服务提供者已经不能进行正常的工作,例如,这个服务提供者需要访问数据库,但是此时数据库已经不能使用了,所以遇到这种情况时,我们可以使用健康监控来处理这类问题。

创建三个项目my-health-server(注册中心)、my-health-provider(服务提供者)、my-health-invoker(服务调用者)

my-health-server源代码如下

pom.xml 如下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.zgy</groupId>
	<artifactId>my-health-server</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>my-health-server</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR5</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

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

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>

复制代码

ServerApp.java 如下

package com.zgy.cloud;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * @EnableEurekaServer:说明该应用是一个Eureka服务器
 */
@SpringBootApplication
@EnableEurekaServer
public class ServerApp {

	public static void main(String[] args) {
		new SpringApplicationBuilder(ServerApp.class).web(true).run(args);
	}
}

复制代码

application.yml 如下

server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
复制代码

my-health-provider源代码如下

pom.xml 如下,引入spring-boot-starter-actuator

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.zgy</groupId>
	<artifactId>my-health-provider</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>my-health-provider</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-eureka</artifactId>
		</dependency>
        
        <dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>
复制代码

ProviderApplication.java 如下

package com.zgy.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @EnableEurekaClient:说明该应用是一个客户端
 */
@SpringBootApplication
@EnableEurekaClient
public class ProviderApplication {

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

复制代码

Police.java 如下

package com.zgy.cloud;

public class Police {

    private Integer id;
    private String name;
    private String message;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

复制代码

PoliceController.java 如下

package com.zgy.cloud;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PoliceController {

    @GetMapping("/call/{id}")
    public Police call(@PathVariable Integer id){
        Police police = new Police();
        police.setId(id);
        police.setName("张三");
        police.setMessage("AAA");

        return police;
    }
}

复制代码

application.yml 如下,关闭敏感端口

spring:
  application:
    name: my-health-provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
endpoints:
  sensitive: false  #关闭健康监控敏感端口
复制代码

my-health-invoker源代码如下

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.zgy</groupId>
	<artifactId>my-health-invoker</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<packaging>jar</packaging>

	<name>my-health-invoker</name>
	<description>Demo project for Spring Boot</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>1.5.13.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<java.version>1.8</java.version>
	</properties>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>Dalston.SR5</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

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

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-ribbon</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>


</project>
复制代码

InvokerApplication.java 如下

package com.zgy.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class InvokerApplication {

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

复制代码

TestController.java 如下

package com.zgy.cloud;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@Configuration
public class TestController {

    /*
    @LoadBalanced:该RestTemplate具有负载均衡的功能
     */
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }

    @GetMapping("/router")
    public String router(){
        RestTemplate restTemplate = getRestTemplate();
        String json = restTemplate.getForObject("http://first-police/call/100", String.class);
        return json;
    }
}

复制代码

application.yml 如下

server:
  port: 8081
spring:
  application:
    name: my-health-invoker
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
复制代码

启动Eureka服务器(my-health-server)和服务提供者(my-health-provider)这两个项目,然后访问http://localhost:8080/health,得到如图所示的结果

注意,"status":"UP"表示该服务提供者现在是正常提供服务的。

然后访问http://localhost:8761/,得到如下图结果

这里也表明该服务提供者现在是正常提供服务的。

然后在PoliceController.java中添加如下代码

/*
    新建一个请求来模拟服务不能正常调用的情况
     */
    public static boolean canVisitDb = true;

    @GetMapping("/db/{can}")
    public void setDb(@PathVariable boolean can){
        canVisitDb = can;
    }
复制代码

新建一个类MyHealthIndicator.java

package com.zgy.cloud;

import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.health.Status;
import org.springframework.stereotype.Component;

@Component
public class MyHealthIndicator implements HealthIndicator{

    @Override
    public Health health() {
        if(PoliceController.canVisitDb){ //如果canVisitDb为true就表示正常提供服务
            return new Health.Builder(Status.UP).build();
        }else{ //如果canVisitDb为false就表示不能正常提供服务
            return new Health.Builder(Status.DOWN).build();
        }
    }
}

复制代码

访问http://localhost:8080/db/true,然后访问http://localhost:8080/health得到下图

表示该服务提供者现在是正常提供服务的

接着访问http://localhost:8080/db/false,然后访问http://localhost:8080/health得到下图

表示该服务提供者现在是不能正常提供服务的

再访问注册中心,http://localhost:8761得到下图

我们发现,注册中心中MY-HEALTH-PROVIDER这个服务依然是UP状态,即表明该服务能正常提供服务,其实该服务已经不能正常提供服务了。

为了能让MY-HEALTH-PROVIDER这个服务,体现出来自己已经不能正常的提供服务,我们需要实现一个健康检查的处理器。

新建一个类MyHealthCheckHandler.java

package com.zgy.cloud;

import com.netflix.appinfo.HealthCheckHandler;
import com.netflix.appinfo.InstanceInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.health.Status;
import org.springframework.stereotype.Component;

@Component
public class MyHealthCheckHandler implements HealthCheckHandler{
    
    @Autowired
    private MyHealthIndicator myHealthIndicator;

    @Override
    public InstanceInfo.InstanceStatus getStatus(InstanceInfo.InstanceStatus instanceStatus) {
        Status status = myHealthIndicator.health().getStatus();
        if(status.equals(Status.UP)){
            return InstanceInfo.InstanceStatus.UP;
        }else{
            return InstanceInfo.InstanceStatus.DOWN;
        }
    }
}

复制代码

修改application.yml添加一个instance-info-replication-interval-seconds配置

spring:
  application:
    name: my-health-provider
eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
    instance-info-replication-interval-seconds: 10 #默认为30秒,意思是在指定的时间里去MyHealthCheckHandler的getStatus方法
endpoints:
  sensitive: false  #关闭健康监控敏感端口

复制代码

访问http://localhost:8080/db/false,过10秒访问http://localhost:8761/,得到下图

说明健康检查处理器已经添加成功

通过服务调用者,再来获取服务列表,测试一下,将服务提供者的状态设置为DOWN状态http://localhost:8080/db/false,然后过10秒访问http://localhost:8081/list,控制台打印如下图信息

从图上,可以看出,服务调用者从注册中心获取的注册列表数据就只有服务调用者本身,说明服务提供者已经从注册中心中剔除掉了。

将服务提供者的状态设置为DOWN状态,http://localhost:8080/db/true,然后过10秒访问http://localhost:8081/list,控制台打印如下图信息

从图上,可以看出,服务调用者从注册中心获取的注册列表数据就有服务调用者本身和服务提供者,说明服务提供者现在又可以正常提供服务了。

总结:

本章的知识点:

  1. 给服务提供者提供心跳检测
  2. 配置服务调用者,在多少秒后去注册中心获取注册列表数据
  3. 元数据的配置
  4. 自我保护模式
  5. 健康监控
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值