使用Spring Boot + Spring Cloud Netflix搭建一套微服务架构解决方案

目前市场上主流的几套微服务架构解决方案分别是:
第一套微服务架构解决方案:SpringBoot + Spring Cloud Netflix
第二套微服务架构解决方案:Spring Boot + Dubbo + Zookeeper
第三套微服务架构解决方案:Spring Boot + Spring Cloud Alibaba
本文主要讲第一套服务架构解决方案**:SpringBoot + Spring Cloud Netflix

1. Spring Cloud Netflix

1.1 简介

Spring Cloud 为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智能路由,微代理,控制总线)。分布式系统的协调导致了样板模式, 使用 Spring Cloud 开发人员可以快速地支持实现这些模式的服务和应用程序。他们将在任何分布式环境中运行良好,包括开发人员自己的笔记本电脑,裸机数据中心,以及 Cloud Foundry 等托管平台。
目前业界对 Spring Cloud 使用最广的就是 Spring Cloud Netflix 了。

2018 年 12 月 12 日,Netflix 宣布 Spring Cloud Netflix 系列技术栈进入维护模式(不再添加新特性)

最近,Netflix 宣布 Hystrix 正在进入维护模式。自 2016 年以来,Ribbon 已处于类似状态。虽然 Hystrix 和 Ribbon 现已处于维护模式,但它们仍然在 Netflix 大规模部署。

Hystrix Dashboard 和 Turbine 已被 Atlas 取代。这些项目的最后一次提交分别是 2 年前和 4 年前。Zuul1 和 Archaius1 都被后来不兼容的版本所取代。

以下 Spring Cloud Netflix 模块和相应的 Starter 将进入维护模式:

  • spring-cloud-netflix-archaius
  • spring-cloud-netflix-hystrix-contract
  • spring-cloud-netflix-hystrix-dashboard
  • spring-cloud-netflix-hystrix-stream
  • spring-cloud-netflix-hystrix
  • spring-cloud-netflix-ribbon
  • spring-cloud-netflix-turbine-stream
  • spring-cloud-netflix-turbine
  • spring-cloud-netflix-zuul

什么是维护模式
将模块置于维护模式,意味着 Spring Cloud 团队将不会再向模块添加新功能。我们将修复 block 级别的 bug 以及安全问题,我们也会考虑并审查社区的小型 pull request。
替代品
我们建议对这些模块提供的功能进行以下替换

CURRENTREPLACEMENT
HystrixResilience4j
Hystrix Dashboard / TurbineMicrometer + Monitoring System
RibbonSpring Cloud Loadbalancer
Zuul 1Spring Cloud Gateway
Archaius 1Spring Boot external config + Spring Cloud Config

其它补充

Netflix Concurrency Limits
并发限制模块,它是 Netflix 开源的限流器项目,Spring Cloud 在 Greenwich 版本中引入 spring-cloud-netflix-concurrency-limits

Archaius 1
有些人对它可能比较陌生,也是 Netflix 公司开源项目,基于 Java 的配置管理类库(apache common configuration 类库的扩展),主要用于多配置存储的动态获取。它主要的特性:

  • 动态类型化属性
  • 高效和线程安全的配置操作
  • 配置改变时的回调机制
  • 轮询框架
  • JMX,通过Jconsole检查和调用操作属性
  • 组合配置

Resilience4j
目前还中孵化中,Spring 可能是要抽象一个断路器的统一规范,让不同的断路器(Hystrix、Resilience4j、Sentinel(阿里开源))选择使用

Micrometer
Spring Boot 2 中的 Spring Boot Actuator 底层用的就是 Micrometer,它是 Pivotal 公司(也就是 Spring 所在的公司)开源的监控门面,类似于监控世界的 Slf4j。Resilience4j 自带整合了 Micrometer;目前还无法判断是否比 Hystrix Dashboard /Turbine 的更强大,更好用。

Spring Cloud Loadbalancer
目前还中孵化中,使用上和 Ribbon 区别不大

Spring Cloud Gateway
Zuul 持续跳票 1 年多,1.x 是一个基于阻塞 IO 的 API Gateway 以及 Servlet;直到 2018 年 5 月,Zuul 2.x(基于 Netty,也是非阻塞的,支持长连接)才发布,但 Spring Cloud 暂时还没有整合计划。Spring Cloud Gateway 比 Zuul 1.x 系列的性能和功能整体要好。

Spring Boot external config + Spring Cloud Config
Netflix 开源的组件(Archaius 1/Ribbon/Hystrix)都没有使用 Spring Boot 的规范(spring-boot-configuration-processor),根本没有 metadata.json 文件,于是这部分配置 IDE 无法给你提示

1.2 概述

Spring Cloud 是一个相对比较新的微服务框架,2016 才推出 1.0 的 Release 版本. 但是其更新特别快,几乎每 1-2 个月就有一次更新,虽然 Spring Cloud 时间最短, 但是相比 Dubbo 等 RPC 框架, Spring Cloud 提供的全套的分布式系统解决方案。

Spring Cloud 为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性 Token,全居琐,Leader 选举,分布式 Session,集群状态)中快速构建的工具,使用 Spring Cloud 的开发者可以快速的启动服务或构建应用、同时能够快速和云平台资源进行对接。

1.3 创建统一的依赖管理

概述
Spring Cloud 项目都是基于 Spring Boot 进行开发,并且都是使用 Maven 做项目管理工具。在实际开发中,我们一般都会创建一个依赖管理项目作为 Maven 的 Parent 项目使用,这样做可以极大的方便我们对 Jar 包版本的统一管理。

创建依赖管理项目
创建一个工程名为 hello-spring-cloud-dependencies 的项目,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>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
    </parent>

    <groupId>com.zhaolei</groupId>
    <artifactId>hello-spring-cloud-dependencies</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    
    <properties>
        <!-- Environment Settings -->
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <!-- Spring Settings -->
            <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
        <!--ZipKin版本号-->
        <zipkin.version>2.10.1</zipkin.version>
        <!--SpringBoot-admin监控管理系统版本号-->
        <spring-boot-admin.version>2.0.1</spring-boot-admin.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>io.zipkin.java</groupId>
                <artifactId>zipkin</artifactId>
                <version>${zipkin.version}</version>
            </dependency>
            <dependency>
                <groupId>io.zipkin.java</groupId>
                <artifactId>zipkin-server</artifactId>
                <version>${zipkin.version}</version>
            </dependency>
            <!--ZipKin所需要的依赖-->
            <dependency>
                <groupId>io.zipkin.java</groupId>
                <artifactId>zipkin-autoconfigure-ui</artifactId>
                <version>${zipkin.version}</version>
            </dependency>
            <!--SpringBootAdmin服务监控与管理所需要的依赖-->
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-starter-server</artifactId>
                <version>${spring-boot-admin.version}</version>
            </dependency>
            <dependency>
                <groupId>de.codecentric</groupId>
                <artifactId>spring-boot-admin-starter-client</artifactId>
                <version>${spring-boot-admin.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <!-- Compiler 插件, 设定 JDK 版本 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <showWarnings>true</showWarnings>
                </configuration>
            </plugin>

            <!-- 打包 jar 文件时,配置 manifest 文件,加入 lib 包的 jar 依赖 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <configuration>
                            <archive>
                                <manifest>
                                    <!-- Add directory entries -->
                                    <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
                                    <addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
                                    <addClasspath>true</addClasspath>
                                </manifest>
                            </archive>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!-- resource -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
            </plugin>

            <!-- install -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-install-plugin</artifactId>
            </plugin>

            <!-- clean -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-clean-plugin</artifactId>
            </plugin>

            <!-- ant -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-antrun-plugin</artifactId>
            </plugin>

            <!-- dependency -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
            </plugin>
        </plugins>

        <pluginManagement>
            <plugins>
                <!-- Java Document Generate -->
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-javadoc-plugin</artifactId>
                    <executions>
                        <execution>
                            <phase>prepare-package</phase>
                            <goals>
                                <goal>jar</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>

                <!-- YUI Compressor (CSS/JS压缩) -->
                <plugin>
                    <groupId>net.alchim31.maven</groupId>
                    <artifactId>yuicompressor-maven-plugin</artifactId>
                    <version>1.5.1</version>
                    <executions>
                        <execution>
                            <phase>prepare-package</phase>
                            <goals>
                                <goal>compress</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <encoding>UTF-8</encoding>
                        <jswarn>false</jswarn>
                        <nosuffix>true</nosuffix>
                        <linebreakpos>30000</linebreakpos>
                        <force>true</force>
                        <includes>
                            <include>**/*.js</include>
                            <include>**/*.css</include>
                        </includes>
                        <excludes>
                            <exclude>**/*.min.js</exclude>
                            <exclude>**/*.min.css</exclude>
                        </excludes>
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>

        <!-- 资源文件配置 -->
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <excludes>
                    <exclude>**/*.java</exclude>
                </excludes>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
            </resource>
        </resources>
    </build>

    <repositories>
        <repository>
            <id>aliyun-repos</id>
            <name>Aliyun Repository</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>

        <repository>
            <id>sonatype-repos</id>
            <name>Sonatype Repository</name>
            <url>https://oss.sonatype.org/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>sonatype-repos-s</id>
            <name>Sonatype Repository</name>
            <url>https://oss.sonatype.org/content/repositories/snapshots</url>
            <releases>
                <enabled>false</enabled>
            </releases>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>

        <repository>
            <id>spring-snapshots</id>
            <name>Spring Snapshots</name>
            <url>https://repo.spring.io/snapshot</url>
            <snapshots>
                <enabled>true</enabled>
            </snapshots>
        </repository>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>

    <pluginRepositories>
        <pluginRepository>
            <id>aliyun-repos</id>
            <name>Aliyun Repository</name>
            <url>http://maven.aliyun.com/nexus/content/groups/public</url>
            <releases>
                <enabled>true</enabled>
            </releases>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </pluginRepository>
    </pluginRepositories>
</project>
  • parent:继承了 Spring Boot 的 Parent,表示我们是一个 Spring Boot 工程
  • package:pom,表示该项目仅当做依赖项目,没有具体的实现代码
  • spring-cloud-dependencies:在 properties 配置中预定义了版本号为 Finchley.RC1 ,表示我们的 - Spring Cloud 使用的是 F 版
  • build:配置了项目所需的各种插件
  • repositories:配置项目下载依赖时的第三方库

在实际开发中,我们所有的项目都会依赖这个 dependencies 项目,整个项目周期中的所有第三方依赖的版本也都由该项目进行管理。

1.4 服务注册与发现(Eureka Server)

概述
在这里,我们需要用的组件是 Spring Cloud Netflix 的 Eureka,Eureka 是一个服务注册和发现模块
创建服务注册中心
创建一个工程名为 hello-spring-cloud-eureka 的项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-eureka</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
        <!--被zipkin服务链路追踪所需要的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--告诉程序的主入口在哪里-->
                    <mainClass>com.zhaolei.hellospringcloud.eureka.EurekaApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

注意这里的mainClass需要指定此工程的主入口

Application
启动一个服务注册中心,只需要一个注解 @EnableEurekaServer

package com.zhaolei.hellospringcloud.eureka;

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

/**
 * @author 15579
 * 文件说明:服务注册与发现端  Eureka服务端
 * 所有服务提供者和消费者都会进入到服务与发现中心
 */
@SpringBootApplication      //这是一个SpringBoot应用程序
@EnableEurekaServer         //开启Eureka服务  启动一个服务注册中心 相当于一个服务器
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

application.yml

spring:
  application:
    name: hello-spring-cloud-eureka

server:
  port: 8761

eureka:
  instance:
#    服务注册中心实例的主机名
    hostname: localhost
  client:
#    是否向服务注册中心注册自己
    registerWithEureka: false
#    是否检索服务
    fetchRegistry: false
    serviceUrl:
#    服务注册中心的配置内容,指定服务注册中心的位置
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

通过 eureka.client.registerWithEureka:falsefetchRegistry:false 来表明自己是一个 Eureka Server.

操作界面
Eureka Server 是有界面的,启动工程,打开浏览器访问:
http://localhost:8761
在这里插入图片描述

1.5 创建服务提供者(Eureka Client)

概述
当 Client(客户端) 向 Server (服务端)注册时,它会提供一些元数据,例如主机和端口,URL,主页等。Eureka Server 从每个 Client 实例接收心跳消息。 如果心跳超时,则通常将该实例从注册 Server 中删除。

创建一个工程名为 hello-spring-cloud-service-admin 的项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-service-admin</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
        <!--被zipkin服务链路追踪所需要的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.zhaolei.hellospringcloud.service.admin.ServiceAdminApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Application
通过注解 @EnableEurekaClient 表明自己是一个 Eureka Client.

package com.zhaolei.hellospringcloud.service.admin;

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

/**
 * @author 15579
 * 文件说明:服务提供者 客户端
 * 以Eureka客户端向Eureka服务端注册
 */
@SpringBootApplication
@EnableEurekaClient  //开启服务客户端向服务端注册功能 
public class ServiceAdminApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceAdminApplication.class,args);
    }
}

application.yml

spring:
  application:
    name: hello-spring-cloud-service-admin

server:
  port: 8762

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

注意: 需要指明 spring.application.name,这个很重要,这在以后的服务与服务之间相互调用一般都是根据这个 name
Controller

package com.zhaolei.hellospringcloud.service.admin.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class AdminController {
  	//注入当前端口号
    @Value("${server.port}")
    private String port;

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam(value = "message") String message) {
        return String.format("Hi,your message is : %s i am from port : %s", message, port);
    }
}

启动工程,打开 http://localhost:8761 ,即 Eureka Server 的网址:
在这里插入图片描述
你会发现一个服务已经注册在服务中了,服务名为 HELLO-SPRING-CLOUD-SERVICE-ADMIN ,端口为 8762

这时打开 http://localhost:8762/hi?message=HelloSpring ,你会在浏览器上看到 :

Hi,your message is :"HelloSpring" i am from port:8762

1.6 创建服务消费者(Ribbon)

概述
在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于 http restful 的。Spring cloud 有两种服务调用方式,一种是 ribbon + restTemplate,另一种是 feign。在这一篇文章首先讲解下基于 ribbon + rest。

Ribbon 简介

Ribbon 是一个负载均衡客户端,可以很好的控制 httptcp 的一些行为。

准备工作

  • 启动服务提供者(本教程案例工程为:hello-spring-cloud-service-admin),端口号为:8762
  • 修改配置文件的端口号为:8763,启动后在 Eureka 中会注册两个实例,这相当于一个小集群(本节最后有在 IDEA 中配置一个工程启动多个实例
    在这里插入图片描述
    创建服务消费者
    创建一个工程名为 hello-spring-cloud-web-admin-ribbon 的服务消费者项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-web-admin-ribbon</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        <!-- Spring Cloud End -->

        <!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
        </dependency>
        <!--Ribbon 中使用熔断器的pom依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <!--被zipkin服务链路追踪所需要的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <!--告诉程序的主入口在哪里-->
                <configuration>
                    <mainClass>com.zhaolei.hellospringcloud.web.admin.ribbon.WebAdminRibbonApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

主要是增加了 Ribbon 的依赖

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

Application
通过 @EnableDiscoveryClient注解注册到服务中心

package com.zhaolei.hellospringcloud.web.admin.ribbon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

/**
 * 文件说明:服务消费者工程(使用Ribbon方式) 服务消费者去调用服务提供者
 * Ribbon 是一个负载均衡客户端,可以很好的控制 http 和 tcp 的一些行为。
 */
@SpringBootApplication
//通过 @EnableDiscoveryClient 注解开启注册到服务中心 
//@EnableDiscoveryClient代表的是服务消费者注册到服务注册中心  
//此注解一般情况下是服务消费者使用
@EnableDiscoveryClient 
public class WebAdminRibbonApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebAdminRibbonApplication.class,args);
    }
}

application.yml
设置程序端口号为:8764

spring:
  application:
    name: hello-spring-cloud-web-admin-ribbon
  thymeleaf:
    cache: false
    mode: LEGACYHTML5
    encoding: UTF-8
    servlet:
      content-type: text/html

server:
  port: 8764

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

Configuration
配置注入 RestTemplate 的 Bean,并通过 @LoadBalanced 注解表明开启负载均衡功能

package com.zhaolei.hellospringcloud.web.admin.ribbon.config;

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

/**
 * @author 15579
 * 文件说明:配置注入 RestTemplate 的 Bean,并通过 @LoadBalanced 注解表明开启负载均衡功能
 */
@Configuration
public class RestTemplateConfiguration {
    @Bean
    @LoadBalanced //注解表明开启负载均衡功能
    public RestTemplate restTemplate(){
        return  new RestTemplate();
    }
}

创建测试用的 Service

在这里我们直接用的程序名替代了具体的 URL 地址,在 Ribbon 中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的 URL 替换掉服务名,代码如下:

package com.zhaolei.hellospringcloud.web.admin.ribbon.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * @author 15579
 * 2019/6/11 10:09
 * 文件说明:创建测试用的 Service
 */
@Service
public class AdminService {
    @Autowired
    private RestTemplate restTemplate;
        public String sayHi(String message) {
        //return restTemplate.getForObject("http://HELLO-SPRING-CLOUD-SERVICE-ADMIN/sayHi?message="+message,String.class);
        //或者使用yml里面的别名
         return restTemplate.getForObject("http://hello-spring-cloud-service-admin/sayHi?message="+message,String.class);
    }
}

创建测试用的 Controller

package com.zhaolei.hellospringcloud.web.admin.ribbon.controller;

import com.zhaolei.hellospringcloud.web.admin.ribbon.service.AdminService;
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.RestController;

@RestController
public class AdminController {

    @Autowired
    private AdminService adminService;

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam String message) {
        return adminService.sayHi(message);
    }
}

测试访问

在浏览器上多次访问 http://localhost:8764/hi?message=HelloRibbon

浏览器交替显示:

Hi,your message is :"HelloRibbon" i am from port:8762
Hi,your message is :"HelloRibbon" i am from port:8763

请求成功则表示我们已经成功实现了负载均衡功能来访问不同端口的实例

此时的架构
在这里插入图片描述

  • 一个服务注册中心,Eureka Server,端口号为:8761
  • service-admin 工程运行了两个实例,端口号分别为:87628763
  • web-admin-ribbon 工程端口号为:8764
  • web-admin-ribbon 通过 RestTemplate 调用 service-admin 接口时因为启用了负载均衡功能故会轮流调用它的 87628763 端口


在 IDEA 中配置一个工程启动多个实例
步骤一
点击 Run -> Edit Configurations...
在这里插入图片描述
步骤二
选择需要启动多实例的项目并去掉 Single instance only 前面的勾
在这里插入图片描述
步骤三
通过修改 application.yml 配置文件的 server.port 的端口,启动多个实例,需要多个端口,分别进行启动即可。

1.7 创建服务消费者(Feign)

概述
Feign 是一个声明式的伪 Http 客户端,它使得写 Http 客户端变得更简单。使用 Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用 Feign 注解和 JAX-RS 注解。Feign 支持可插拔的编码器和解码器。Feign 默认集成了 Ribbon,并和 Eureka 结合,默认实现了负载均衡的效果

  • Feign 采用的是基于接口的注解
  • Feign 整合了 ribbon

创建服务消费者

创建一个工程名为 hello-spring-cloud-web-admin-feign 的服务消费者项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-web-admin-feign</artifactId>
    <packaging>jar</packaging>

    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- Spring Cloud End -->

        <!-- 解决 thymeleaf 模板引擎一定要执行严格的 html5 格式校验问题 -->
        <dependency>
            <groupId>net.sourceforge.nekohtml</groupId>
            <artifactId>nekohtml</artifactId>
        </dependency>

        <!--使用熔断器仪表盘监控所需要的pom依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
        </dependency>
        <!--分布式配置客户端  使用云yml配置所需要的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!--被zipkin服务链路追踪所需要的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--告诉程序的主入口在哪里-->
                    <mainClass>com.zhaolei.hellospringcloud.web.admin.feign.WebAdminFeignApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

主要是增加了 Feign 的依赖

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

Application
通过 @EnableFeignClients 注解开启 Feign 功能

package com.zhaolei.hellospringcloud.web.admin.feign;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
import org.springframework.cloud.openfeign.EnableFeignClients;

/**
 * @author 15579
 * 文件说明:创建服务消费者工程 (使用feign方式)
 * Feign 是一个声明式的伪 Http 客户端,它使得写 Http 客户端变得更简单。
 * 使用 Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,
 * 可使用 Feign 注解和 JAX-RS 注解。Feign 支持可插拔的编码器和解码器。
 * Feign 默认集成了 Ribbon,并和 Eureka 结合,默认实现了负载均衡的效果
 */
@SpringBootApplication
@EnableFeignClients // @EnableFeignClients注解开启 Feign 功能
@EnableDiscoveryClient //通过 @EnableDiscoveryClient 注解开启注册到服务中心
// EnableDiscoveryClient代表的就是服务消费者注册到服务注册中心
@EnableHystrixDashboard     //@EnableHystrixDashboard  开启熔断器仪表盘监控
public class WebAdminFeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebAdminFeignApplication.class,args);
    }
}

application.yml
设置程序端口号为:8765

spring:
  application:
    name: hello-spring-cloud-web-admin-feign
  thymeleaf:
    cache: false
    mode: LEGACYHTML5
    encoding: UTF-8
    servlet:
      content-type: text/html

server:
  port: 8765

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

创建 Feign 接口
通过 @FeignClient("服务名")注解来指定调用哪个服务。代码如下:

package com.zhaolei.hellospringcloud.web.admin.feign.service;

import com.zhaolei.hellospringcloud.web.admin.feign.service.hystrix.AdminServiceHystrix;
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 15579
 * 文件说明:Feign 接口
 */
//@FeignClient指定调用服务提供者的应用程序名
@FeignClient(value = "hello-spring-cloud-service-admin")
public interface AdminService {

	//这里写服务提供者对应方法的访问路径
    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam(value = "message") String message);
}

创建测试用的 Controller

package com.zhaolei.hellospringcloud.web.admin.feign.controller;

import com.zhaolei.hellospringcloud.web.admin.feign.service.AdminService;
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.RestController;


@RestController
public class AdminController {

    @Autowired
    private AdminService adminService;

    @RequestMapping(value = "hi", method = RequestMethod.GET)
    public String sayHi(@RequestParam String message) {
        return adminService.sayHi(message);
    }
}

测试访问
在浏览器上多次访问 http://localhost:8765/hi?message=HelloFeign

浏览器交替显示:

Hi,your message is :"HelloFeign" i am from port:8762
Hi,your message is :"HelloFeign" i am from port:8763

请求成功则表示我们已经成功实现了 Feign 功能来访问不同端口(负载均衡)的实例

1.8 使用熔断器防止服务雪崩(Hystrix)

概述
在微服务架构中,根据业务来拆分成一个个的服务,服务与服务之间可以通过 RPC 相互调用,在 Spring Cloud 中可以用 RestTemplate + Ribbon 和 Feign 来调用。为了保证其高可用,单个服务通常会集群部署。由于网络原因或者自身的原因,服务并不能保证 100% 可用,如果单个服务出现问题,调用这个服务就会出现线程阻塞,此时若有大量的请求涌入,Servlet 容器的线程资源会被消耗完毕,导致服务瘫痪。服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的 “雪崩” 效应。

为了解决这个问题,业界提出了熔断器模型。

Netflix 开源了 Hystrix 组件,实现了熔断器模式,Spring Cloud 对这一组件进行了整合。在微服务架构中,一个请求需要调用多个服务是非常常见的,如下图:
在这里插入图片描述
较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystrix 是 5 秒 20 次) 熔断器将会被打开。

在这里插入图片描述
熔断器打开后,为了避免连锁故障,通过 fallback方法可以直接返回一个固定值。

Ribbon 中使用熔断器

hello-spring-cloud-web-admin-ribbon项目的 pom.xml 中增加依赖(在讲Ribbon工程时我已加入如果是复制的整个pom文件就已经导入了,看看自己的pom文件有没有这个依赖)

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

在 Application 中增加 @EnableHystrix 注解

package com.zhaolei.hellospringcloud.web.admin.ribbon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

/**
 * 文件说明:服务消费者工程(使用Ribbon方式) 服务消费者去调用服务提供者
 * Ribbon 是一个负载均衡客户端,可以很好的控制 http 和 tcp 的一些行为。
 */
@SpringBootApplication
//通过 @EnableDiscoveryClient 注解开启注册到服务中心 
//@EnableDiscoveryClient代表的是服务消费者注册到服务注册中心  
//此注解一般情况下是服务消费者使用
@EnableDiscoveryClient
@EnableHystrix      //@EnableHystrix  开启熔断器 
public class WebAdminRibbonApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebAdminRibbonApplication.class,args);
    }
}

在 Service 中增加 @HystrixCommand 注解
在 Ribbon 调用方法上增加 @HystrixCommand 注解并指定 fallbackMethod 熔断方法

package com.zhaolei.hellospringcloud.web.admin.ribbon.service;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

/**
 * @author 15579
 * 文件说明:创建测试用的 Service
 */
@Service
public class AdminService {
    @Autowired
    private RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "sayHiError")    //通过 @HystrixCommand中的fallbackMethod指定熔断方法
    public String sayHi(String message){
        //return restTemplate.getForObject("http://HELLO-SPRING-CLOUD-SERVICE-ADMIN/sayHi?message="+message,String.class);
        //或者使用yml里面的别名
         return restTemplate.getForObject("http://hello-spring-cloud-service-admin/sayHi?message="+message,String.class);
    }

    /**
     * sayHi方法的熔断方法
     * @param message
     * @return
     */
    public String sayHiError(String message){
        return String.format("Hi SpringCloud Message:%s but request bad",message);
    }
}

测试熔断器
此时我们关闭服务提供者(停止hello-spring-cloud-service-admin工程),再次请求 http://localhost:8764/hi?message=HelloRibbon 浏览器会显示:

Hi SpringCloud Message:HelloRibbon but request bad

Feign 中使用熔断器

Feign 是自带熔断器的,但默认是关闭的。需要在配置文件中配置打开它,在hello-spring-cloud-web-admin-feign配置文件增加以下代码:

# 开启熔断器     Feign 是自带熔断器的,但默认是关闭的
feign:
  hystrix:
    enabled: true

创建熔断器类并实现对应的 Feign 接口

package com.zhaolei.hellospringcloud.web.admin.feign.service.hystrix;

import com.zhaolei.hellospringcloud.web.admin.feign.service.AdminService;
import org.springframework.stereotype.Component;

/**
 * @author 15579
 * 文件说明:AdminService的熔断实现类
 */
@Component      //表明这是一个组件类
public class AdminServiceHystrix implements AdminService {
    @Override
    public String sayHi(String message) {
        return String.format("Hi SpringCloud Message:%s but request bad",message);
    }
}

在 Service 中增加 fallback 指定类

package com.zhaolei.hellospringcloud.web.admin.feign.service;

import com.zhaolei.hellospringcloud.web.admin.feign.service.hystrix.AdminServiceHystrix;
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 15579
 * 文件说明:Feign测试接口
 */
//@FeignClient指定调用服务提供者的应用程序名
@FeignClient(value = "hello-spring-cloud-service-admin",fallback = AdminServiceHystrix.class)
//fallback指定熔断回调类
public interface AdminService {
    @RequestMapping(value = "/sayHi",method = RequestMethod.GET)    //这里写服务提供者对应方法的访问路径
    public String sayHi(@RequestParam("message")String message);
}

测试熔断器
此时我们关闭服务提供者,再次请求 http://localhost:8765/hi?message=HelloFeign 浏览器会显示:

Hi SpringCloud Message:HelloFeign but request bad

1.9 使用熔断器仪表盘监控

概述
在 Ribbon 和 Feign 项目增加 Hystrix 仪表盘功能,两个项目的改造方式相同
pom.xml 中增加依赖(前面我创建项目时pom文件已写入,如果没有自己添加进去)

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId>
</dependency>

在 Application 中增加 @EnableHystrixDashboard 注解

package com.zhaolei.hellospringcloud.web.admin.ribbon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

/**
 * 文件说明:服务消费者工程(使用Ribbon方式) 服务消费者去调用服务提供者
 * Ribbon 是一个负载均衡客户端,可以很好的控制 http 和 tcp 的一些行为。
 */
@SpringBootApplication
//通过 @EnableDiscoveryClient 注解开启注册到服务中心 
//@EnableDiscoveryClient代表的是服务消费者注册到服务注册中心  
//此注解一般情况下是服务消费者使用
@EnableDiscoveryClient
@EnableHystrix      //@EnableHystrix  开启熔断器 
@EnableHystrixDashboard     //@EnableHystrixDashboard  开启熔断器仪表盘监控
public class WebAdminRibbonApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebAdminRibbonApplication.class,args);
    }
}

创建 hystrix.stream 的 Servlet 配置

Spring Boot 2.x 版本开启 Hystrix Dashboard 与 Spring Boot 1.x 的方式略有不同,需要增加一个 HystrixMetricsStreamServlet 的配置,代码如下:

package com.zhaolei.hellospringcloud.web.admin.ribbon.config;

import com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author 15579
 * 文件说明:创建 hystrix.stream 的 Servlet 配置
 */
@Configuration
public class HystrixDashboardConfiguration {
    @Bean   //注入bean
    public ServletRegistrationBean getServlet() {
        HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();  //创建自己的servlet
        ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);  //注册servlet
        registrationBean.setLoadOnStartup(1);               //启动顺序
        registrationBean.addUrlMappings("/hystrix.stream");     //Servlet的访问路径
        registrationBean.setName("HystrixMetricsStreamServlet");//Servlet的名字
        return registrationBean;
    }
}

测试 Hystrix Dashboard
浏览器端访问 http://localhost:8764/hystrix 界面如下:
在这里插入图片描述
点击 Monitor Stream,进入下一个界面,访问http://localhost:8764/hi?message=HelloRibbon 此时会出现监控界面:
在这里插入图片描述
附:Hystrix 说明

什么情况下会触发 fallback 方法

名字描述触发 fallback
EMIT值传递NO
SUCCESS执行完成,没有错误NO
FAILURE执行抛出异常YES
TIMEOUT执行开始,但没有在允许的时间内完成YES
BAD_REQUEST执行抛出HystrixBadRequestExceptionNO
SHORT_CIRCUITED断路器打开,不尝试执行YES
THREAD_POOL_REJECTED断路器打开,不尝试执行YES
SEMAPHORE_REJECTED断路器打开,不尝试执行YES

fallback 方法在什么情况下会抛出异常

名字描述抛异常
FALLBACK_EMITFallback值传递NO
FALLBACK_SUCCESSFallback执行完成,没有错误NO
FALLBACK_FAILUREFallback执行抛出出错YES
FALLBACK_REJECTEDFallback信号量拒绝,不尝试执行YES
FALLBACK_MISSING没有Fallback实例YES

Hystrix Dashboard 界面监控参数
在这里插入图片描述
Hystrix 常用配置信息

超时时间(默认1000ms,单位:ms)

  • hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds:在调用方配置,被该调用方的所有方法的超时时间都是该值,优先级低于下边的指定配置
  • hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds:在调用方配置,被该调用方的指定方法(HystrixCommandKey 方法名)的超时时间是该值

线程池核心线程数
hystrix.threadpool.default.coreSize:默认为 10

Queue

  • hystrix.threadpool.default.maxQueueSize:最大排队长度。默认 -1,使用 SynchronousQueue。其他值则使用 LinkedBlockingQueue。如果要从 -1 换成其他值则需重启,即该值不能动态调整,若要动态调整,需要使用到下边这个配置
  • hystrix.threadpool.default.queueSizeRejectionThreshold:排队线程数量阈值,默认为 5,达到时拒绝,如果配置了该选项,队列的大小是该队列
    注意: 如果 maxQueueSize=-1 的话,则该选项不起作用

断路器

  • hystrix.command.default.circuitBreaker.requestVolumeThreshold:当在配置时间窗口内达到此数量的失败后,进行短路。默认 20 个(10s 内请求失败数量达到 20 个,断路器开)
  • hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds:短路多久以后开始尝试是否恢复,默认 5s
  • hystrix.command.default.circuitBreaker.errorThresholdPercentage:出错百分比阈值,当达到此阈值后,开始短路。默认 50%

fallback

  • hystrix.command.default.fallback.isolation.semaphore.maxConcurrentRequests:调用线程允许请求 HystrixCommand.GetFallback()的最大数量,默认 10。超出时将会有异常抛出,注意:该项配置对于 THREAD 隔离模式也起作用

属性配置参数

1.10 使用路由网关统一访问接口(Zuul)

概述
在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、熔断器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简单的微服务系统如下图:
在这里插入图片描述
在 Spring Cloud 微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Zuul、Ngnix),再到达服务网关(Zuul 集群),然后再到具体的服。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在 GIT 仓库,方便开发人员随时改配置。

Zuul 简介
Zuul 的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如 /api/user 转发到到 User 服务,/api/shop 转发到到 Shop 服务。Zuul 默认和 Ribbon 结合实现了负载均衡的功能。

创建路由网关
创建一个工程名为 hello-spring-cloud-zuul的项目,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>

   <parent>
       <groupId>com.zhaolei</groupId>
       <artifactId>hello-spring-cloud-dependencies</artifactId>
       <version>1.0.0-SNAPSHOT</version>
       <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
   </parent>

   <artifactId>hello-spring-cloud-zuul</artifactId>
   <packaging>jar</packaging>
   <dependencies>
       <!-- Spring Boot Begin -->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-tomcat</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-actuator</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
       <!-- Spring Boot End -->

       <!-- Spring Cloud Begin -->
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
       </dependency>
       <!--zuul路由网关pom依赖-->
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
       </dependency>
       <!-- Spring Cloud End -->
       <!--被zipkin服务链路追踪所需要的依赖-->
       <dependency>
           <groupId>org.springframework.cloud</groupId>
           <artifactId>spring-cloud-starter-zipkin</artifactId>
       </dependency>
       <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
       <dependency>
           <groupId>org.jolokia</groupId>
           <artifactId>jolokia-core</artifactId>
       </dependency>
       <dependency>
           <groupId>de.codecentric</groupId>
           <artifactId>spring-boot-admin-starter-client</artifactId>
       </dependency>
       <!--end-->
   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
               <configuration>
                   <!--告诉程序的入口在哪里-->
                   <mainClass>com.zhaolei.hellospringcloud.zuul.ZuulApplication</mainClass>
               </configuration>
           </plugin>
       </plugins>
   </build>
</project>

主要是增加了 Zuul 的依赖

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

Application
增加 @EnableZuulProxy 注解开启 Zuul 功能

package com.zhaolei.hellospringcloud.zuul;


import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
/**
 * @author 15579
 * 文件说明:Zuul路由网关统一调用服务消费者
 * Zuul 的主要功能是路由转发和过滤器。路由功能是微服务的一部分,
 * 比如 /api/user 转发到到 User 服务,/api/shop 转发到到 Shop 服务。
 * Zuul 默认和 Ribbon 结合实现了负载均衡的功能。
 *
 */
@SpringBootApplication
@EnableEurekaClient             //开启注册到Eureka客户端 @EnableEurekaClient 代表的就是服务提供者
@EnableZuulProxy            //开启Zuul路由网关功能
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}

application.yml

  • 设置端口号为:8769
  • 增加 Zuul 配置
spring:
  application:
    name: hello-spring-cloud-zuul
  #      服务链路追踪工程地址
  zipkin:
    base-url: http://localhost:9411
  #    服务监控和管理服务端工程地址
  boot:
    admin:
      client:
        url: http://localhost:8084
server:
  port: 8769

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

zuul:
  routes:
    api-a:
      path: /api/a/**
      serviceId: hello-spring-cloud-web-admin-ribbon
    api-b:
      path: /api/b/**
      serviceId: hello-spring-cloud-web-admin-feign

#  自己定义服务名
#api-a:
# path: /api/a/**  访问路径  ** 匹配所有
#      path: /api/a/**
#     serviceId 对应服务消费者别名
#      serviceId: hello-spring-cloud-web-admin-ribbon
#      以 /api/a 开头的请求都转发给 hello-spring-cloud-web-admin-ribbon 服务

路由说明:

  • /api/a 开头的请求都转发给 hello-spring-cloud-web-admin-ribbon 服务
  • /api/b开头的请求都转发给 hello-spring-cloud-web-admin-feign 服务

测试访问

依次运行 EurekaApplicationServiceAdminApplicationWebAdminRibbonApplicationWebAdminFeignApplicationZuulApplication

打开浏览器访问:http://localhost:8769/api/a/hi?message=HelloZuul浏览器显示

Hi,your message is :"HelloZuul" i am from port:8763

打开浏览器访问:http://localhost:8769/api/b/hi?message=HelloZuul 浏览器显示

Hi,your message is :"HelloZuul" i am from port:8763

至此说明 Zuul 的路由功能配置成功

配置网关路由失败时的回调(每一个路由都要配置这里我暂时只配置了feign的)

package com.zhaolei.hellospringcloud.zuul.provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

/**
 * @author 15579
 * 文件说明:为每一个服务创建一个回调(feign)
 * hello-spring-cloud-web-admin-feign 失败时的回调
 *  配置网关路由失败时的回调
 */

@Component //组件
public class WebAdminFeignFallbackProvider implements FallbackProvider {
    //失败时调用的方法
    @Override
    public String getRoute() {
        // ServiceId,如果需要所有调用都支持回退,则 return "*" 或 return null
        return "hello-spring-cloud-web-admin-feign";
    }

    /**
     * 如果请求服务失败,则返回指定的信息给调用者
     * @param route
     * @param cause
     * @return
     */
    @Override
    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
        return new ClientHttpResponse() {
            /**
             * 网关向 api 服务请求失败了,但是消费者客户端向网关发起的请求是成功的,
             * 不应该把 api 的 404,500 等问题抛给客户端
             * 网关和 api 服务集群对于客户端来说是黑盒
             * @return
             * @throws IOException
             */
            @Override
            public HttpStatus getStatusCode() throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode() throws IOException {
                return HttpStatus.OK.value();
            }

            @Override
            public String getStatusText() throws IOException {
                return HttpStatus.OK.getReasonPhrase();
            }

            @Override
            public void close() {

            }

            @Override
            public InputStream getBody() throws IOException {
                ObjectMapper objectMapper = new ObjectMapper();
                Map<String, Object> map = new HashMap<>();
                map.put("status", 200);
                //抛给用户消息
                map.put("message", "无法连接,请检查您的网络");
                return new ByteArrayInputStream(objectMapper.writeValueAsString(map).getBytes("UTF-8"));
            }

            @Override
            public HttpHeaders getHeaders() {
                HttpHeaders headers = new HttpHeaders();
                // 和 getBody 中的内容编码一致
                headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
                return headers;
            }
        };
    }
}


1.11 使用路由网关的服务过滤功能

概述

Zuul 不仅仅只是路由,还有很多强大的功能,本节演示一下它的服务过滤功能,比如用在安全验证方面。

创建服务过滤器
继承 ZuulFilter 类并在类上增加 @Component 注解就可以使用服务过滤功能了,非常简单方便

package com.zhaolei.hellospringcloud.zuul.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author 15579
 * 2019/6/14 17:05
 * 文件说明:路由登陆过滤器
 */
@Component
public class LoginFilter extends ZuulFilter {
    private static final Logger logger = (Logger) LoggerFactory.getLogger(LoginFilter.class);
    /**
     * 配置过滤类型,有四种不同生命周期的过滤器类型
     * 1. pre:路由之前
     * 2. routing:路由之时
     * 3. post:路由之后
     * 4. error:发送错误调用
     * @return
     */
    @Override
    public String filterType() {
        //再路由发起请求之前
        return "pre";
    }

    /**
     * 配置过滤的顺序
     * 数值越小执行越靠前
     * @return
     */
    @Override
    public int filterOrder() {
        return 0;
    }

    /**
     * 配置是否需要过滤:true/需要,false/不需要
     * @return
     */
    @Override
    public boolean shouldFilter() {
        return true;
    }

    /**
     * 过滤器的具体业务代码
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();    //得到当前请求上下文
        HttpServletRequest request = context.getRequest();
        logger.info("{} >>> {}", request.getMethod(), request.getRequestURL().toString());
        String token = request.getParameter("token");       //得到参数
        if (token == null) {
            logger.warn("Token is empty");
            context.setSendZuulResponse(false);     //禁止发送zuul路由请求
            context.setResponseStatusCode(401);     //响应请求
            try {
                HttpServletResponse response=context.getResponse();
                response.setContentType("text/html;charset=utf-8"); //设置响应编码格式
                context.getResponse().getWriter().write("Token is empty");  //提示消息
            } catch (IOException e) {
                logger.error(e.getMessage());
            }
        } else {
            logger.info("OK");
        }
        return null;
    }
}

filterType

返回一个字符串代表过滤器的类型,在 Zuul 中定义了四种不同生命周期的过滤器类型

  • pre:路由之前
  • routing:路由之时
  • post: 路由之后
  • error:发送错误调用

filterOrder

过滤的顺序

shouldFilter

是否需要过滤,这里是 true,需要过滤

run

过滤器的具体业务代码

测试过滤器
浏览器访问:http://localhost:8769/api/a/hi?message=HelloZuul 网页显示

Token is empty

浏览器访问:http://localhost:8769/api/b/hi?message=HelloZuul&token=123 网页显示

Hi,your message is :"HelloZuul" i am from port:8763

2. Spring Cloud 服务配置

2.1 分布式配置中心

概述

在分布式系统中,由于服务数量巨多,为了方便服务配置文件统一管理,实时更新,所以需要分布式配置中心组件。在 Spring Cloud 中,有分布式配置中心组件 Spring Cloud Config ,它支持配置服务放在配置服务的内存中(即本地),也支持放在远程 Git 仓库中。在 Spring Cloud Config 组件中,分两个角色,一是 Config Server,二是 Config Client。

2.2 分布式配置中心服务端(Config server)

前提条件:

实现分布式配置中心的前提条件:在自己的git建一个仓库再建立一个repo文件夹所有yml配置文件都放这个repo文件夹里然后克隆到本地,我这里已经导入到项目里了:
在这里插入图片描述
在这里插入图片描述

概述
创建一个工程名为 hello-spring-cloud-config 的项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-config</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->

        <!--被zipkin服务链路追踪所需要的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

        <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--告诉程序的主入口在哪里-->
                    <mainClass>com.zhaolei.hellospringcloud.config.ConfigApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

主要增加了 spring-cloud-config-server 依赖

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

Application

通过 @EnableConfigServer 注解,开启配置服务器功能

package com.zhaolei.hellospringcloud.config;

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

/**
 * @author 15579
 * 2019/6/15 11:15
 * 文件说明:分布式配置中心服务端
 */
@SpringBootApplication
@EnableEurekaClient         //开启注册到服务注册中心 EnableEurekaClient表示服务提供者
@EnableConfigServer         //开启配置服务器功能
public class ConfigApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication.class,args);
    }
}

application.yml

增加 Config 相关配置,并设置端口号为:8888

spring:
  application:
    name: hello-spring-cloud-config
  cloud:
    config:
      label: master
      server:
        git:
          uri: https://gitee.com/riven666/springcloud-config.git
          search-paths: respo
          username: ***
          password: ***
server:
  port: 8888

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

#  spring.cloud.config.label:配置仓库的分支
#  spring.cloud.config.server.git.uri:配置 Git 仓库地址(GitHub、GitLab、码云 ...)
#  spring.cloud.config.server.git.search-paths:配置仓库路径(存放配置文件的目录)
#  spring.cloud.config.server.git.username:访问 Git 仓库的账号
#  spring.cloud.config.server.git.password:访问 Git 仓库的密码

相关配置说明,如下:

  • spring.cloud.config.label:配置仓库的分支
  • spring.cloud.config.server.git.uri:配置 Git 仓库地址(GitHub、GitLab、码云 …)
  • spring.cloud.config.server.git.search-paths:配置仓库路径(存放配置文件的目录)
  • spring.cloud.config.server.git.username:访问 Git 仓库的账号
  • spring.cloud.config.server.git.password:访问 Git 仓库的密码

注意事项:

  • 如果使用 GitLab 作为仓库的话,git.uri 需要在结尾加上 .git,GitHub 则不用

启动工程测试
浏览器端访问:http://localhost:8888/config-client/dev/master 显示如下:

<Environment> 
  <name>config-client</name>  
  <profiles> 
    <profiles>dev</profiles> 
  </profiles>  
  <label>master</label>  
  <version>9646007f931753d7e96a6dcc9ae34838897a91df</version>  
  <state/>  
  <propertySources> 
    <propertySources> 
      <name>https://github.com/topsale/spring-cloud-config/respo/config-client-dev.yml</name>  
      <source> 
        <foo>foo version 1</foo>  
        <demo.message>Hello Spring Config</demo.message> 
      </source> 
    </propertySources> 
  </propertySources> 
</Environment>

证明配置服务中心可以从远程程序获取配置信息

附:HTTP 请求地址和资源文件映射

  • http://ip:port/{application}/{profile}[/{label}]
  • http://ip:port/{application}-{profile}.yml
  • http://ip:port/{label}/{application}-{profile}.yml
  • http://ip:port/{application}-{profile}.properties
  • http://ip:port/{label}/{application}-{profile}.properties

2.3 分布式配置中心客户端(Config client)

概述
有两种创建Config 客户端方式

第一种Config client方式

创建一个工程名为 hello-spring-cloud-config-client 的项目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>

    <parent>
        <groupId>com.zhaoeli</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-config-client</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
            <!--被zipkin服务链路追踪所需要的依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>

        <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.zhaolei.hello.spring.cloud.config.client.ConfigClientApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

主要增加了 spring-cloud-starter-config 依赖

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

Application

入口类没有需要特殊处理的地方,代码如下:

package com.zhaolei.hello.spring.cloud.config.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class ConfigClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigClientApplication.class, args);
    }
}

application.yml
增加 Config Client 相关配置,并设置端口号为:8889

spring:
  application:
    name: hello-spring-cloud-config-client
  cloud:
    config:
      uri: http://localhost:8888
      name: config-client
      label: master
      profile: dev

server:
  port: 8889

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

相关配置说明,如下:

  • spring.cloud.config.uri:配置服务中心的网址
  • spring.cloud.config.name:配置文件名称的前缀
  • spring.cloud.config.label:配置仓库的分支
  • spring.cloud.config.profile:配置文件的环境标识
  • dev:表示开发环境
  • test:表示测试环境
  • prod:表示生产环境

注意事项:

  • 配置服务器的默认端口为 8888,如果修改了默认端口,则客户端项目就不能在 application.ymlapplication.properties 中配置 spring.cloud.config.uri,必须在 bootstrap.yml 或是 bootstrap.properties 中配置,原因是 bootstrap 开头的配置文件会被优先加载和配置,切记。

创建测试用 Controller

我们创建一个 Controller 来测试一下通过远程仓库的配置文件注入 foo 属性

package com.zhaolei.hello.spring.cloud.config.client.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestConfigController {

    @Value("${foo}")
    private String foo;

    @RequestMapping(value = "/hi", method = RequestMethod.GET)
    public String hi() {
        return foo;
    }
}

一般情况下,能够正常启动服务就说明注入是成功的。

测试访问

浏览器端访问:http://localhost:8889/hi 显示如下:

foo version 1

附:开启 Spring Boot Profile

我们在做项目开发的时候,生产环境和测试环境的一些配置可能会不一样,有时候一些功能也可能会不一样,所以我们可能会在上线的时候手工修改这些配置信息。但是 Spring 中为我们提供了 Profile 这个功能。我们只需要在启动的时候添加一个虚拟机参数,激活自己环境所要用的 Profile 就可以了。

操作起来很简单,只需要为不同的环境编写专门的配置文件,如:application-dev.yml、application-prod.yml, 启动项目时只需要增加一个命令参数 --spring.profiles.active=环境配置 即可,启动命令如下:

java -jar hello-spring-cloud-web-admin-feign-1.0.0-SNAPSHOT.jar --spring.profiles.active=prod

第二种Config client方式

1、将你所需要做分布式配置的工程导入pom依赖(我这里以hello-spring-cloud-web-admin-feign为例,前面引入pom文件时我已加入,没有的自行添加):

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

2、在从git上克隆的respo的文件夹上添加两个yml文件,将hello-spring-cloud-web-admin-feign工程的yml全部配置剪切过来效果图如下(我这里创建了两个dev是开发环境使用,prod是生产环境使用):
在这里插入图片描述
web-admin-feign-dev.yml代码如下(web-admin-feign-prod.yml只是端口号不同):

# 开发环境
spring:
  application:
    name: hello-spring-cloud-web-admin-feign
  thymeleaf:
    cache: false
    mode: LEGACYHTML5
    encoding: UTF-8
    servlet:
      content-type: text/html
server:
  port: 8765

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
# 开启熔断器     Feign 是自带熔断器的,但默认是关闭的
feign:
  hystrix:
    enabled: true

3、将修改后的文件commit到git仓库(整个仓库都提交)
4、hello-spring-cloud-web-admin-feign的yml改为如下代码:

spring:
#  分布式云配置中心地址
  cloud:
    config:
      uri: http://localhost:8888
      name: web-admin-feign
      label: master
      profile: dev
  • name 对应的是你在git仓库创建的yml文件名
  • profile 对应的环境
    在这里插入图片描述

重启hello-spring-cloud-web-admin-feign工程

在浏览器上访问 http://localhost:8765/hi?message=HelloFeign
显示结果如下:

Hi,your message is :"HelloFeign" i am from port:8762

说明分布式配置中心客户端创建成功,其他工程想实现此效果也是相同的操作

3. Spring Cloud 服务追踪

3.1 服务链路追踪(ZipKin)

ZipKin 简介

ZipKin 是一个开放源代码的分布式跟踪系统,由 Twitter 公司开源,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,包括数据的收集、存储、查找和展现。它的理论模型来自于 Google Dapper 论文。

每个服务向 ZipKin 报告计时数据,ZipKin 会根据调用关系通过 ZipKin UI 生成依赖关系图,显示了多少跟踪请求通过每个服务,该系统让开发者可通过一个 Web 前端轻松的收集和分析数据,例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。

服务追踪说明

微服务架构是通过业务来划分服务的,使用 REST 调用。对外暴露的一个接口,可能需要很多个服务协同才能完成这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败。随着业务的不断扩张,服务之间互相调用会越来越复杂。
在这里插入图片描述
随着服务的越来越多,对调用链的分析会越来越复杂。它们之间的调用关系也许如下:
在这里插入图片描述
术语解释

  • Span:基本工作单元,例如,在一个新建的 Span 中发送一个 RPC 等同于发送一个回应请求给 RPC,Span 通过一个 64 位 ID 唯一标识,Trace 以另一个 64 位 ID 表示。
  • Trace:一系列 Spans 组成的一个树状结构,例如,如果你正在运行一个分布式大数据工程,你可能需要创建一个 Trace。
  • Annotation:用来即使记录一个事件的存在,一些核心 Annotations 用来定义一个请求的开始和结束
    1、cs:Client Sent,客户端发起一个请求,这个 Annotation 描述了这个 Span 的开始
    2、sr:Server Received,服务端获得请求并准备开始处理它,如果将其 sr 减去 cs 时间戳便可得到网络延迟
    3、ss:Server Sent 表明请求处理的完成(当请求返回客户端),如果 ss 减去 sr 时间戳便可得到服务端需要的处理请求时间
    4、cr:Client Received 表明 Span 的结束,客户端成功接收到服务端的回复,如果 cr 减去 cs 时间戳便可得到客户端从服务端获取回复的所有所需时间

将 Span 和 Trace 在一个系统中使用 Zipkin 注解的过程图形化:
在这里插入图片描述
创建 ZipKin 服务端

创建一个工程名为 hello-spring-cloud-zipkin 的项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-zipkin</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-server</artifactId>
        </dependency>
        <dependency>
            <groupId>io.zipkin.java</groupId>
            <artifactId>zipkin-autoconfigure-ui</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
        <!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--告诉程序的主入口在哪里-->
                    <mainClass>com.zhaolei.hellospringcloud.zipkin.ZipKinApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

主要增加了 3 个依赖,io.zipkin.java:zipkinio.zipkin.java:zipkin-serverio.zipkin.java:zipkin-autoconfigure-ui

<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-server</artifactId>
</dependency>
<dependency>
    <groupId>io.zipkin.java</groupId>
    <artifactId>zipkin-autoconfigure-ui</artifactId>
</dependency>

注意版本号为:2.10.1,这里没写版本号是因为我已将版本号托管到 dependencies 项目中

Application

通过 @EnableZipkinServer注解开启 Zipkin Server 功能

package com.zhaolei.hellospringcloud.zipkin;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import zipkin.server.internal.EnableZipkinServer;

/**
 * 2019/6/17 10:12
 * 文件说明:服务链路追踪工程
 * ZipKin 是一个开放源代码的分布式跟踪系统,由 Twitter 公司开源
 * ,它致力于收集服务的定时数据,以解决微服务架构中的延迟问题,
 * 包括数据的收集、存储、查找和展现。它的理论模型来自于 Google Dapper 论文。
 *
 * 每个服务向 ZipKin 报告计时数据,ZipKin 会根据调用关系通过 ZipKin UI 生成依赖关系图,
 * 显示了多少跟踪请求通过每个服务,该系统让开发者可通过一个 Web 前端轻松的收集和分析数据,
 * 例如用户每次请求服务的处理时间等,可方便的监测系统中存在的瓶颈。
 */
@SpringBootApplication
@EnableEurekaClient         //@EnableEurekaClient 开启注册到服务注册与发现 @EnableEurekaClient代表这是个服务提供者
@EnableZipkinServer         //@EnableZipkinServer 开启服务链路追踪功能
public class ZipKinApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZipKinApplication.class,args);
    }
}

application.yml

spring:
  application:
    name: hello-spring-cloud-zipkin

server:
  port: 9411

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
      
management:
  metrics:
    web:
      server:
        auto-time-requests: false

追踪服务

所有需要被追踪的项目(就当前教程而言,除了 dependencies 项目外都需要被追踪,包括 Eureka Server) 中增加 spring-cloud-starter-zipkin 依赖

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

在这些项目的 application.yml 配置文件中增加 Zipkin Server 的地址即可

spring:
  zipkin:
    base-url: http://localhost:9411

测试追踪

启动全部项目,打开浏览器访问:http://localhost:9411/ 会出现以下界面:

在这里插入图片描述
刷新之前项目中的全部测试接口(刷多几次)

点击 Find a trace,可以看到具体服务相互调用的数据
在这里插入图片描述
点击 Dependencies,可以发现服务的依赖关系
在这里插入图片描述
至此就代表 ZipKin 配置成功

3.2 Spring Boot Admin

简介

随着开发周期的推移,项目会不断变大,切分出的服务也会越来越多,这时一个个的微服务构成了错综复杂的系统。对于各个微服务系统的健康状态、会话数量、并发数、服务资源、延迟等度量信息的收集就成为了一个挑战。Spring Boot Admin 应运而生,它正式基于这些需求开发出的一套功能强大的监控管理系统。

Spring Boot Admin 有两个角色组成,一个是 Spring Boot Admin Server,一个是 Spring Boot Admin Client,本章节将带领大家实现 Spring Boot Admin 的搭建。

3.3 Spring Boot Admin 服务端

创建 Spring Boot Admin Server
创建一个工程名为 hello-spring-cloud-admin 的项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-admin</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-server</artifactId>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--告诉程序的主入口在哪里-->
                    <mainClass>com.zhaolei.hellospringcloud.admin.AdminApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

主要增加了 2 个依赖,org.jolokia:jolokia-corede.codecentric:spring-boot-admin-starter-server

<dependency>
    <groupId>org.jolokia</groupId>
    <artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-server</artifactId>
</dependency>

其中 spring-boot-admin-starter-server 的版本号为:2.0.0,这里没写版本号是因为我已将版本号托管到 dependencies 项目中

Application
通过 @EnableAdminServer 注解开启 Admin 功能

package com.zhaolei.hellospringcloud.admin;

import de.codecentric.boot.admin.server.config.EnableAdminServer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
* @author 15579
* 文件说明:SpringCloud微服务架构的监控管理工程(服务端)
* 随着开发周期的推移,项目会不断变大,切分出的服务也会越来越多,
* 这时一个个的微服务构成了错综复杂的系统。对于各个微服务系统的
* 健康状态、会话数量、并发数、服务资源、延迟等度量信息的收集就成为了一个挑战。
* Spring Boot Admin 应运而生,它正式基于这些需求开发出的一套功能强大的监控管理系统
*/
@SpringBootApplication
@EnableEurekaClient    //开启注册到Eureka服务注册与发现 EnableEurekaClient表示这是一个服务提供者
@EnableAdminServer      //开启SpringBootAdmin监控管理系统  服务端
public class AdminApplication {
   public static void main(String[] args) {
       SpringApplication.run(AdminApplication.class,args);
   }
}

application.yml
设置端口号为:8084

spring:
  application:
    name: hello-spring-cloud-admin
  zipkin:
    base-url: http://localhost:9411

server:
  port: 8084

management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: health,info

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

主要增加了 Spring Boot Admin Server 的相关配置

management:
  endpoint:
    health:
      show-details: always
  endpoints:
    web:
      exposure:
        include: health,info

测试访问监控中心
打开浏览器访问:http://localhost:8084 会出现以下界面
在这里插入图片描述

3.4 Spring Boot Admin 客户端

创建 Spring Boot Admin Client
创建一个工程名为 hello-spring-cloud-admin-client 的项目,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>

    <parent>
        <groupId>com.zhaolei</groupId>
        <artifactId>hello-spring-cloud-dependencies</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../hello-spring-cloud-dependencies/pom.xml</relativePath>
    </parent>

    <artifactId>hello-spring-cloud-admin-client</artifactId>
    <packaging>jar</packaging>
    <dependencies>
        <!-- Spring Boot Begin -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!-- Spring Boot End -->

        <!-- Spring Cloud Begin -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- Spring Cloud End -->
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.zhaolei.hello.spring.cloud.admin.client.AdminClientApplication</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

主要增加了 2 个依赖,org.jolokia:jolokia-corede.codecentric:spring-boot-admin-starter-client

<dependency>
    <groupId>org.jolokia</groupId>
    <artifactId>jolokia-core</artifactId>
</dependency>
<dependency>
    <groupId>de.codecentric</groupId>
    <artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>

其中 spring-boot-admin-starter-client 的版本号为:2.0.0,这里没写版本号是因为我已将版本号托管到 dependencies项目中

Application

程序入口类没有特别需要修改的地方

package com.zhaolei.hello.spring.cloud.admin.client;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class AdminClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(AdminClientApplication.class, args);
    }
}

application.yml
设置端口号为:8085,并设置 Spring Boot Admin 的服务端地址

spring:
  application:
    name: hello-spring-cloud-admin-client
  boot:
    admin:
      client:
        url: http://localhost:8084
  zipkin:
    base-url: http://localhost:9411

server:
  port: 8085

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/

主要增加了 Spring Boot Admin Client 相关配置

spring:
  boot:
    admin:
      client:
        url: http://localhost:8084

测试服务监控

依次启动两个应用,打开浏览器访问:http://localhost:8084 界面显示如下
在这里插入图片描述
从图中可以看到,我们的 Admin Client 已经上线了,至此说明监控中心搭建成功

WallBoard(当前只有一个服务被监控)
在这里插入图片描述
Journal
在这里插入图片描述
监控整个SpringCloud项目的所有服务
在 所有需要被监控的项目(就当前教程而言,除了 dependencies 项目外都需要被追踪,包括 Eureka Server) 中增加 org.jolokia:jolokia-corede.codecentric:spring-boot-admin-starter-client 依赖

<!--SpringBoot-Admin-client客户端所需要的依赖(被SpringBoot-Admin-server服务端所监控和管理)begin-->
        <dependency>
            <groupId>org.jolokia</groupId>
            <artifactId>jolokia-core</artifactId>
        </dependency>
        <dependency>
            <groupId>de.codecentric</groupId>
            <artifactId>spring-boot-admin-starter-client</artifactId>
        </dependency>
        <!--end-->

在这些项目的 application.yml 配置文件中增加 SpringBoot Admin Server 的地址即可

spring:
  #    服务监控和管理服务端工程地址
  boot:
    admin:
      client:
        url: http://localhost:8084

启动全部项目,打开浏览器访问:http://localhost:8084 会出现以下界面:
在这里插入图片描述
所有服务都被监控了

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值