blog

vuePress-theme-reco blog    2019 - 2020
blog blog

Choose mode

  • dark
  • auto
  • light
Home
Category
  • Linux
  • java
  • java 后端
  • typora
  • vue
  • java 基础
  • 编程方法
  • Mysql
Tag
TimeLine
在线工具
  • PDF 转换器
  • JSON 编辑器
  • MD 表格生成器
  • CRON 表达式
  • 代码格式化
  • 公式编辑器
  • 二维码生成器
  • 在线编码转换
  • YAML <-> Properties
  • 在线 Web 练习
Contact
  • GitHub
  • 简书
  • CSDN
  • 博客圆
  • WeChat
author-avatar

blog

23

文章

16

标签

Home
Category
  • Linux
  • java
  • java 后端
  • typora
  • vue
  • java 基础
  • 编程方法
  • Mysql
Tag
TimeLine
在线工具
  • PDF 转换器
  • JSON 编辑器
  • MD 表格生成器
  • CRON 表达式
  • 代码格式化
  • 公式编辑器
  • 二维码生成器
  • 在线编码转换
  • YAML <-> Properties
  • 在线 Web 练习
Contact
  • GitHub
  • 简书
  • CSDN
  • 博客圆
  • WeChat
  • Spring Cloud Netfilx

    • 简介
      • 概述
    • 创建统一的依赖管理
      • 概述
      • 查看SpringBoot和SpringCloud版本对应关系
      • 创建依赖管理项目
    • 服务注册与发现
      • 概述
      • 创建服务注册中心
      • 操作界面
    • 创建服务提供者
      • 概述
      • POM
      • Application
      • pplication.yml
      • Controller
    • 创建服务消费者(Ribbon)
      • 概述
      • Ribbon 简介
      • 准备工作
      • 创建服务消费者
      • 此时的架构
      • 附
    • 创建服务消费者(Feign)
      • 概述
      • 创建服务消费者
    • 使用熔断器防止服务雪崩
      • 概述
      • Ribbon 中使用熔断器
      • Feign 中使用熔断器
    • 使用熔断器仪表盘监控
      • 概述
      • pom.xml 中增加依赖
      • 在 Application 中增加 @EnableHystrixDashboard 注解
      • 创建 hystrix.stream 的 Servlet 配置
      • 测试 Hystrix Dashboard
      • 附:Hystrix 说明
    • 使用路由网关统一访问接口
      • 概述
      • Zuul 简介
      • 创建路由网关
      • 测试访问
      • 配置网关路由失败时的回调
    • 使用路由网关的服务过滤功能
      • 概述
      • 创建服务过滤器
      • 测试过滤器
    • 分布式配置中心
      • 分布式配置中心服务端
        • 概述
        • Application
        • application.yml
        • 测试
        • 附:HTTP 请求地址和资源文件映射
      • 分布式配置中心客户端
        • 概述
        • Application
        • application.yml
        • 创建测试用 Controller
        • 测试访问
        • 附:开启 Spring Boot Profile
      • 服务链路追踪
        • 概述
        • ZipKin 简介
        • 服务追踪说明
        • 术语解释
        • 创建 ZipKin 服务端
        • Application
        • application.yml
        • 追踪服务
        • 测试追踪
      • Spring Boot Admin
        • Spring Boot Admin 服务端
          • 创建 Spring Boot Admin Server
          • Application
          • application.yml
        • 测试访问监控中心
          • Spring Boot Admin 客户端
            • 创建 Spring Boot Admin Client
            • Application
            • application.yml
            • 测试服务监控

        Spring Cloud Netfilx

        vuePress-theme-reco blog    2019 - 2020

        Spring Cloud Netfilx


        blog 2019-10-10 spring cloud

        # 简介

        # 概述

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

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

        # 创建统一的依赖管理

        # 概述

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

        # 查看SpringBoot和SpringCloud版本对应关系

        官网

        "spring-cloud": {
              "Finchley.M2": "Spring Boot >=2.0.0.M3 and <2.0.0.M5",
              "Finchley.M3": "Spring Boot >=2.0.0.M5 and <=2.0.0.M5",
              "Finchley.M4": "Spring Boot >=2.0.0.M6 and <=2.0.0.M6",
              "Finchley.M5": "Spring Boot >=2.0.0.M7 and <=2.0.0.M7",
              "Finchley.M6": "Spring Boot >=2.0.0.RC1 and <=2.0.0.RC1",
              "Finchley.M7": "Spring Boot >=2.0.0.RC2 and <=2.0.0.RC2",
              "Finchley.M9": "Spring Boot >=2.0.0.RELEASE and <=2.0.0.RELEASE",
              "Finchley.RC1": "Spring Boot >=2.0.1.RELEASE and <2.0.2.RELEASE",
              "Finchley.RC2": "Spring Boot >=2.0.2.RELEASE and <2.0.3.RELEASE",
              "Finchley.SR4": "Spring Boot >=2.0.3.RELEASE and <2.0.999.BUILD-SNAPSHOT",
              "Finchley.BUILD-SNAPSHOT": "Spring Boot >=2.0.999.BUILD-SNAPSHOT and <2.1.0.M3",
              "Greenwich.M1": "Spring Boot >=2.1.0.M3 and <2.1.0.RELEASE",
              "Greenwich.SR3": "Spring Boot >=2.1.0.RELEASE and <2.1.10.BUILD-SNAPSHOT",
              "Greenwich.BUILD-SNAPSHOT": "Spring Boot >=2.1.10.BUILD-SNAPSHOT and <2.2.0.M4",
              "Hoxton.M2": "Spring Boot >=2.2.0.M4 and <2.2.0.BUILD-SNAPSHOT",
              "Hoxton.BUILD-SNAPSHOT": "Spring Boot >=2.2.0.BUILD-SNAPSHOT"
            },
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18

        # 创建依赖管理项目

        创建一个工程名为 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.funtl</groupId>
            <artifactId>hello-spring-cloud-dependencies</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <packaging>pom</packaging>
        
            <name>hello-spring-cloud-dependencies</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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.RC1</spring-cloud.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>
                </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>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89
        90
        91
        92
        93
        94
        95
        96
        97
        98
        99
        100
        101
        102
        103
        104
        105
        106
        107
        108
        109
        110
        111
        112
        113
        114
        115
        116
        117
        118
        119
        120
        121
        122
        123
        124
        125
        126
        127
        128
        129
        130
        131
        132
        133
        134
        135
        136
        137
        138
        139
        140
        141
        142
        143
        144
        145
        146
        147
        148
        149
        150
        151
        152
        153
        154
        155
        156
        157
        158
        159
        160
        161
        162
        163
        164
        165
        166
        167
        168
        169
        170
        171
        172
        173
        174
        175
        176
        177
        178
        179
        180
        181
        182
        183
        184
        185
        186
        187
        188
        189
        190
        191
        192
        193
        194
        195
        196
        197
        198
        199
        200
        201
        202
        203
        204
        205
        206
        207
        208
        209
        210
        211
        212
        213
        214
        215
        216
        217
        218
        219
        220
        221
        222
        223
        224
        225
        226
        227
        228
        229
        230
        231
        232
        233
        234
        235
        236
        237
        238
        239
        • parent:继承了 Spring Boot 的 Parent,表示我们是一个 Spring Boot 工程
        • package:pom,表示该项目仅当做依赖项目,没有具体的实现代码
        • spring-cloud-dependencies:在 properties 配置中预定义了版本号为 Finchley.RC1 ,表示我们的 Spring Cloud 使用的是 F 版
        • build:配置了项目所需的各种插件
        • repositories:配置项目下载依赖时的第三方库

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

        # 服务注册与发现

        # 概述

        在这里,我们需要用的组件是 Spring Cloud Netflix 的 Eureka,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.funtl</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>
        
            <name>hello-spring-cloud-eureka</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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 -->
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.eureka.EurekaApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48

        # Application

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

        package com.funtl.hello.spring.cloud.eureka;
        
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
        
        @SpringBootApplication
        @EnableEurekaServer
        public class EurekaApplication {
            public static void main(String[] args) {
                SpringApplication.run(EurekaApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        # application.yml

        Eureka 是一个高可用的组件,它没有后端缓存,每一个实例注册之后需要向注册中心发送心跳(因此可以在内存中完成),在默认情况下 Erureka Server 也是一个 Eureka Client ,必须要指定一个 Server。

        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/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

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

        # 操作界面

        Eureka Server 是有界面的,启动工程,打开浏览器访问:

        http://localhost:8761

        img

        # 创建服务提供者

        # 概述

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

        # POM

        <?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.funtl</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>
        
            <name>hello-spring-cloud-service-admin</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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 -->
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.service.admin.ServiceAdminApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48

        # Application

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

        package com.funtl.hello.spring.cloud.service.admin;
        
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
        
        @SpringBootApplication
        @EnableEurekaClient
        public class ServiceAdminApplication {
            public static void main(String[] args) {
                SpringApplication.run(ServiceAdminApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        # pplication.yml

        spring:
          application:
            name: hello-spring-cloud-service-admin
        
        server:
          port: 8762
        
        eureka:
          client:
            serviceUrl:
              defaultZone: http://localhost:8761/eureka/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11

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

        # Controller

        package com.funtl.hello.spring.cloud.service.admin.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.RequestParam;
        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);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19

        启动工程,打开 http://localhost:8761 ,即 Eureka Server 的网址:

        img

        你会发现一个服务已经注册在服务中了,服务名为 HELLO-SPRING-CLOUD-SERVICE-ADMIN ,端口为 8762

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

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

        # 创建服务消费者(Ribbon)

        # 概述

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

        # Ribbon 简介

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

        # 准备工作

        • 启动服务提供者(本教程案例工程为:hello-spring-cloud-service-admin),端口号为:8762
        • 修改配置文件的端口号为:8763,启动后在 Eureka 中会注册两个实例,这相当于一个小集群

        img

        # 创建服务消费者

        创建一个工程名为 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.funtl</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>
        
            <name>hello-spring-cloud-web-admin-ribbon</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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>
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.web.admin.ribbon.WebAdminRibbonApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74

        主要是增加了 Ribbon 的依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>
        
        1
        2
        3
        4

        # Application

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

        package com.funtl.hello.spring.cloud.web.admin.ribbon;
        
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
        
        @SpringBootApplication
        @EnableDiscoveryClient
        public class WebAdminRibbonApplication {
            public static void main(String[] args) {
                SpringApplication.run(WebAdminRibbonApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        # 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/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17

        # Configuration

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

        package com.funtl.hello.spring.cloud.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;
        
        @Configuration
        public class RestTemplateConfiguration {
        
            @Bean
            @LoadBalanced
            public RestTemplate restTemplate() {
                return new RestTemplate();
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16

        # 创建测试用的 Service

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

        package com.funtl.hello.spring.cloud.web.admin.ribbon.service;
        
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.stereotype.Service;
        import org.springframework.web.client.RestTemplate;
        
        @Service
        public class AdminService {
        
            @Autowired
            private RestTemplate restTemplate;
        
            public String sayHi(String message) {
                return restTemplate.getForObject("http://HELLO-SPRING-CLOUD-SERVICE-ADMIN/hi?message=" + message, String.class);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16

        # 创建测试用的 Controller

        package com.funtl.hello.spring.cloud.web.admin.ribbon.controller;
        
        import com.funtl.hello.spring.cloud.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.RequestParam;
        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);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20

        # 测试访问

        在浏览器上多次访问 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
        
        1
        2

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

        # 此时的架构

        img

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

        # 附

        # 在 IDEA 中配置一个工程启动多个实例

        # 步骤一

        点击 Run -> Edit Configurations...

        img

        # 步骤二

        选择需要启动多实例的项目并去掉 Single instance only 前面的勾

        img

        # 步骤三

        通过修改 application.yml 配置文件的 server.port 的端口,启动多个实例,需要多个端口,分别进行启动即可。

        # 创建服务消费者(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.funtl</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>
        
            <name>hello-spring-cloud-web-admin-feign</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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>
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.web.admin.feign.WebAdminFeignApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74

        主要是增加了 Feign 的依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        
        1
        2
        3
        4

        # Application

        通过 @EnableFeignClients 注解开启 Feign 功能

        package com.funtl.hello.spring.cloud.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.openfeign.EnableFeignClients;
        
        @SpringBootApplication
        @EnableDiscoveryClient
        @EnableFeignClients
        public class WebAdminFeignApplication {
            public static void main(String[] args) {
                SpringApplication.run(WebAdminFeignApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

        # 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/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17

        # 创建 Feign 接口

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

        package com.funtl.hello.spring.cloud.web.admin.feign.service;
        
        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;
        
        @FeignClient(value = "hello-spring-cloud-service-admin")
        public interface AdminService {
        
            @RequestMapping(value = "hi", method = RequestMethod.GET)
            public String sayHi(@RequestParam(value = "message") String message);
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        # 创建测试用的 Controller

        package com.funtl.hello.spring.cloud.web.admin.feign.controller;
        
        import com.funtl.hello.spring.cloud.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.RequestParam;
        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);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20

        # 测试访问

        在浏览器上多次访问 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
        
        1
        2

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

        # 使用熔断器防止服务雪崩

        # 概述

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

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

        Netflix 开源了 Hystrix 组件,实现了熔断器模式,Spring Cloud 对这一组件进行了整合。在微服务架构中,一个请求需要调用多个服务是非常常见的,如下图:

        img

        较底层的服务如果出现故障,会导致连锁故障。当对特定的服务的调用的不可用达到一个阀值(Hystrix 是 5 秒 20 次) 熔断器将会被打开。

        img

        熔断器打开后,为了避免连锁故障,通过 fallback 方法可以直接返回一个固定值。

        # Ribbon 中使用熔断器

        # 在 pom.xml 中增加依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        
        1
        2
        3
        4

        # Application 中增加 @EnableHystrix 注解

        package com.funtl.hello.spring.cloud.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;
        
        @SpringBootApplication
        @EnableDiscoveryClient
        @EnableHystrix
        public class WebAdminRibbonApplication {
            public static void main(String[] args) {
                SpringApplication.run(WebAdminRibbonApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

        # 在 Service 中增加 @HystrixCommand 注解

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

        package com.funtl.hello.spring.cloud.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;
        
        @Service
        public class AdminService {
        
            @Autowired
            private RestTemplate restTemplate;
        
            @HystrixCommand(fallbackMethod = "hiError")
            public String sayHi(String message) {
                return restTemplate.getForObject("http://HELLO-SPRING-CLOUD-SERVICE-ADMIN/hi?message=" + message, String.class);
            }
        
            public String hiError(String message) {
                return "Hi,your message is :\"" + message + "\" but request error.";
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22

        # 测试熔断器

        此时我们关闭服务提供者,再次请求 http://localhost:8764/hi?message=HelloRibbon 浏览器会显示:

        Hi,your message is :"HelloRibbon" but request error.
        
        1

        # Feign 中使用熔断器

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

        feign:
          hystrix:
            enabled: true
        
        1
        2
        3

        # 在 Service 中增加 fallback 指定类

        package com.funtl.hello.spring.cloud.web.admin.feign.service;
        
        import com.funtl.hello.spring.cloud.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;
        
        @FeignClient(value = "hello-spring-cloud-service-admin", fallback = AdminServiceHystrix.class)
        public interface AdminService {
        
            @RequestMapping(value = "hi", method = RequestMethod.GET)
            public String sayHi(@RequestParam(value = "message") String message);
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14

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

        package com.funtl.hello.spring.cloud.web.admin.feign.service.hystrix;
        
        import com.funtl.hello.spring.cloud.web.admin.feign.service.AdminService;
        import org.springframework.stereotype.Component;
        
        @Component
        public class AdminServiceHystrix implements AdminService {
        
            @Override
            public String sayHi(String message) {
                return "Hi,your message is :\"" + message + "\" but request error.";
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        # 测试熔断器

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

        Hi,your message is :"HelloFeign" but request error.
        
        1

        # 使用熔断器仪表盘监控

        # 概述

        在 Ribbon 和 Feign 项目增加 Hystrix 仪表盘功能,两个项目的改造方式相同

        # pom.xml 中增加依赖

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

        # 在 Application 中增加 @EnableHystrixDashboard 注解

        package com.funtl.hello.spring.cloud.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;
        import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard;
        
        @SpringBootApplication
        @EnableDiscoveryClient
        @EnableHystrix
        @EnableHystrixDashboard
        public class WebAdminRibbonApplication {
            public static void main(String[] args) {
                SpringApplication.run(WebAdminRibbonApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17

        # 创建 hystrix.stream 的 Servlet 配置

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

        package com.funtl.hello.spring.cloud.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;
        
        @Configuration
        public class HystrixDashboardConfiguration {
        
            @Bean
            public ServletRegistrationBean getServlet() {
                HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();
                ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);
                registrationBean.setLoadOnStartup(1);
                registrationBean.addUrlMappings("/hystrix.stream");
                registrationBean.setName("HystrixMetricsStreamServlet");
                return registrationBean;
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20

        # 测试 Hystrix Dashboard

        浏览器端访问 http://localhost:8764/hystrix 界面如下:

        img

        点击 Monitor Stream,进入下一个界面,访问 http://localhost:8764/hi?message=HelloRibbon 此时会出现监控界面:

        img

        # 附:Hystrix 说明

        # 什么情况下会触发 fallback 方法

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

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

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

        # Hystrix Dashboard 界面监控参数

        img

        # 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 隔离模式也起作用

        # 属性配置参数

        • 参数说明:https://github.com/Netflix/Hystrix/wiki/Configuration
        • HystrixProperty 参考代码:http://www.programcreek.com/java-api-examples/index.php?source_dir=Hystrix-master/hystrix-contrib/hystrix-javanica/src/test/java/com/netflix/hystrix/contrib/javanica/test/common/configuration/command/BasicCommandPropertiesTest.java

        # 使用路由网关统一访问接口

        # 概述

        在微服务架构中,需要几个基础的服务治理组件,包括服务注册与发现、服务消费、负载均衡、熔断器、智能路由、配置管理等,由这几个基础组件相互协作,共同组建了一个简单的微服务系统。一个简单的微服务系统如下图:

        img

        在 Spring Cloud 微服务系统中,一种常见的负载均衡方式是,客户端的请求首先经过负载均衡(Zuul、Ngnix),再到达服务网关(Zuul 集群),然后再到具体的服。服务统一注册到高可用的服务注册中心集群,服务的所有的配置文件由配置服务管理,配置服务的配置文件放在 GIT 仓库,方便开发人员随时改配置。

        # Zuul 简介

        Zuul 的主要功能是路由转发和过滤器。路由功能是微服务的一部分,比如 /api/user 转发到到 User 服务,/api/shop 转发到到 Shop 服务。Zuul 默认和 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.funtl</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>
        
            <name>hello-spring-cloud-zuul</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
                </dependency>
                <!-- Spring Cloud End -->
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.zuul.ZuulApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64

        主要是增加了 Zuul 的依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
        
        1
        2
        3
        4

        # Application

        增加 @EnableZuulProxy 注解开启 Zuul 功能

        package com.funtl.hello.spring.cloud.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;
        
        @SpringBootApplication
        @EnableEurekaClient
        @EnableZuulProxy
        public class ZuulApplication {
            public static void main(String[] args) {
                SpringApplication.run(ZuulApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

        # application.yml

        • 设置端口号为:8769
        • 增加 Zuul 配置
        spring:
          application:
            name: hello-spring-cloud-zuul
        
        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
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20

        路由说明:

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

        # 测试访问

        依次运行 EurekaApplication、ServiceAdminApplication、WebAdminRibbonApplication、WebAdminFeignApplication、ZuulApplication

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

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

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

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

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

        # 配置网关路由失败时的回调

        package com.funtl.hello.spring.cloud.zuul.fallback;
        
        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;
        
        /**
         * 路由 hello-spring-cloud-web-admin-feign 失败时的回调
         * <p>Title: WebAdminFeignFallbackProvider</p>
         * <p>Description: </p>
         *
         * @author Lusifer
         * @version 1.0.0
         * @date 2018/7/27 6:55
         */
        @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
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82
        83
        84
        85
        86
        87
        88
        89

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

        # 概述

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

        # 创建服务过滤器

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

        package com.funtl.hello.spring.cloud.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 java.io.IOException;
        
        /**
         * Zuul 的服务过滤演示
         * <p>Title: LoginFilter</p>
         * <p>Description: </p>
         *
         * @author Lusifer
         * @version 1.0.0
         * @date 2018/5/29 22:02
         */
        @Component
        public class LoginFilter extends ZuulFilter {
        
            private static final 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);
                    context.setResponseStatusCode(401);
                    try {
                        context.getResponse().getWriter().write("Token is empty");
                    } catch (IOException e) {
                    }
                } else {
                    logger.info("OK");
                }
                return null;
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77
        78
        79
        80
        81
        82

        # filterType

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

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

        # filterOrder

        过滤的顺序

        # shouldFilter

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

        # run

        过滤器的具体业务代码

        # 测试过滤器

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

        Token is empty
        
        1

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

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

        # Spring Cloud 服务配置

        # 分布式配置中心

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

        # 分布式配置中心服务端

        # 概述

        创建一个工程名为 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.funtl</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>
        
            <name>hello-spring-cloud-config</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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 -->
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.config.ConfigApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        
        1
        2
        3
        4

        # Application

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

        package com.funtl.hello.spring.cloud.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;
        
        @SpringBootApplication
        @EnableConfigServer
        @EnableEurekaClient
        public class ConfigApplication {
            public static void main(String[] args) {
                SpringApplication.run(ConfigApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

        # application.yml

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

        spring:
          application:
            name: hello-spring-cloud-config
          cloud:
            config:
              label: master
              server:
                git:
                  uri: https://github.com/topsale/spring-cloud-config
                  search-paths: respo
                  username:
                  password:
        
        server:
          port: 8888
        
        eureka:
          client:
            serviceUrl:
              defaultZone: http://localhost:8761/eureka/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20

        相关配置说明,如下:

        • 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>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18

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

        # 附: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

        # 分布式配置中心客户端

        # 概述

        创建一个工程名为 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.funtl</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>
        
            <name>hello-spring-cloud-config-client</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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 -->
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.config.client.ConfigClientApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        
        1
        2
        3
        4

        # Application

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

        package com.funtl.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);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        # 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/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17

        相关配置说明,如下:

        • spring.cloud.config.uri:配置服务中心的网址

        • spring.cloud.config.name:配置文件名称的前缀

        • spring.cloud.config.label:配置仓库的分支

        • spring.cloud.config.profile
          
          1

          :配置文件的环境标识

          • dev:表示开发环境
          • test:表示测试环境
          • prod:表示生产环境

        注意事项:

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

        # 创建测试用 Controller

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

        package com.funtl.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;
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18

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

        # 测试访问

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

        foo version 1
        
        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
        
        1

        # Spring Cloud 服务追踪

        # 服务链路追踪

        # 概述

        这篇文章主要讲解服务追踪组件 ZipKin。

        # ZipKin 简介

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

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

        # 服务追踪说明

        微服务架构是通过业务来划分服务的,使用 REST 调用。对外暴露的一个接口,可能需要很多个服务协同才能完成这个接口功能,如果链路上任何一个服务出现问题或者网络超时,都会形成导致接口调用失败。随着业务的不断扩张,服务之间互相调用会越来越复杂。

        img

        随着服务的越来越多,对调用链的分析会越来越复杂。它们之间的调用关系也许如下:

        img

        # 术语解释

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

        将 Span 和 Trace 在一个系统中使用 Zipkin 注解的过程图形化:

        img

        # 创建 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.funtl</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>
        
            <name>hello-spring-cloud-zipkin</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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 -->
            </dependencies>
        
            <build>
                <plugins>
                    <plugin>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-maven-plugin</artifactId>
                        <configuration>
                            <mainClass>com.funtl.hello.spring.cloud.zipkin.ZipKinApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72

        主要增加了 3 个依赖,io.zipkin.java:zipkin、io.zipkin.java:zipkin-server、io.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>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12

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

        # Application

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

        package com.funtl.hello.spring.cloud.zipkin;
        
        import org.springframework.boot.SpringApplication;
        import org.springframework.boot.autoconfigure.SpringBootApplication;
        import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
        import zipkin.server.internal.EnableZipkinServer;
        
        @SpringBootApplication
        @EnableEurekaClient
        @EnableZipkinServer
        public class ZipKinApplication {
            public static void main(String[] args) {
                SpringApplication.run(ZipKinApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

        # application.yml

        设置端口号为:9411,该端口号为 Zipkin Server 的默认端口号

        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
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17

        # 追踪服务

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

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zipkin</artifactId>
        </dependency>
        
        1
        2
        3
        4

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

        spring:
          zipkin:
            base-url: http://localhost:9411
        
        1
        2
        3

        # 测试追踪

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

        img

        刷新之前项目中的全部测试接口(刷多几次)

        点击 Find a trace,可以看到具体服务相互调用的数据

        img

        点击 Dependencies,可以发现服务的依赖关系

        img

        至此就代表 ZipKin 配置成功

        # Spring Boot Admin

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

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

        # 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.funtl</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>
        
            <name>hello-spring-cloud-admin</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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.funtl.hello.spring.cloud.admin.AdminApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73
        74
        75
        76
        77

        主要增加了 2 个依赖,org.jolokia:jolokia-core、de.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>
        
        1
        2
        3
        4
        5
        6
        7
        8

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

        # Application

        通过 @EnableAdminServer 注解开启 Admin 功能

        package com.funtl.hello.spring.cloud.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;
        
        @SpringBootApplication
        @EnableEurekaClient
        @EnableAdminServer
        public class AdminApplication {
            public static void main(String[] args) {
                SpringApplication.run(AdminApplication.class, args);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15

        # 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"] 但已无效了,请修改
                include: health,info
        
        eureka:
          client:
            serviceUrl:
              defaultZone: http://localhost:8761/eureka/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23

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

        management:
          endpoint:
            health:
              show-details: always
          endpoints:
            web:
              exposure:
                # 注意:此处在视频里是 include: ["health", "info"] 但已无效了,请修改
                include: health,info
        
        1
        2
        3
        4
        5
        6
        7
        8
        9

        # 测试访问监控中心

        打开浏览器访问:http://localhost:8084 会出现以下界面

        img

        # 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.funtl</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>
        
            <name>hello-spring-cloud-admin-client</name>
            <url>http://www.funtl.com</url>
            <inceptionYear>2018-Now</inceptionYear>
        
            <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.funtl.hello.spring.cloud.admin.client.AdminClientApplication</mainClass>
                        </configuration>
                    </plugin>
                </plugins>
            </build>
        </project>
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        44
        45
        46
        47
        48
        49
        50
        51
        52
        53
        54
        55
        56
        57
        58
        59
        60
        61
        62
        63
        64
        65
        66
        67
        68
        69
        70
        71
        72
        73

        主要增加了 2 个依赖,org.jolokia:jolokia-core、de.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>
        
        1
        2
        3
        4
        5
        6
        7
        8

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

        # Application

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

        package com.funtl.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);
            }
        }
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13

        # 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/
        
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17

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

        spring:
          boot:
            admin:
              client:
                url: http://localhost:8084
        
        1
        2
        3
        4
        5

        # 测试服务监控

        依次启动两个应用,打开浏览器访问:http://localhost:8084 界面显示如下

        img

        从图中可以看到,我们的 Admin Client 已经上线了,至此说明监控中心搭建成功

        # WallBoard

        img

        # Journal

        img