# SpringCloud系列

\[TOC]

## SpringCloud系列

> 以下内容，均在搭建 [lemon](https://github.com/ATSJP/lemon) 项目时，收集和写下的一些内容，如有错误欢迎指正>>>[@SJP](mailto:shijianpeng2010@163.com)

### 实际中应用及推荐文章

推荐文章：<https://blog.csdn.net/zrl0506/article/details/80165477>

![1548589316026](/files/UYkOabvFET5z1y1B1NiR)

推荐文章：<https://blog.csdn.net/qq\\_37170583/article/details/80704904>

### SpringCloud和SpringBoot对应版本

官方文档：<http://spring.io/projects/spring-cloud（一切始于官方文档）>

**Table1**

| SpringCloud | SpringBoot |
| ----------- | ---------- |
| Greenwich   | 2.1.X      |
| Finchley    | 2.0.X      |
| Edgware     | 1.5.x      |
| Dalston     | 1.5.x      |

**Table2**

| Component                 | Edgware.SR5    | Finchley.SR2  | Finchley.BUILD-SNAPSHOT |
| ------------------------- | -------------- | ------------- | ----------------------- |
| spring-cloud-aws          | 1.2.3.RELEASE  | 2.0.1.RELEASE | 2.0.1.BUILD-SNAPSHOT    |
| spring-cloud-bus          | 1.3.3.RELEASE  | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT    |
| spring-cloud-cli          | 1.4.1.RELEASE  | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT    |
| spring-cloud-commons      | 1.3.5.RELEASE  | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-contract     | 1.2.6.RELEASE  | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-config       | 1.4.5.RELEASE  | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-netflix      | 1.4.6.RELEASE  | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-security     | 1.2.3.RELEASE  | 2.0.1.RELEASE | 2.0.1.BUILD-SNAPSHOT    |
| spring-cloud-cloudfoundry | 1.1.2.RELEASE  | 2.0.1.RELEASE | 2.0.1.BUILD-SNAPSHOT    |
| spring-cloud-consul       | 1.3.5.RELEASE  | 2.0.1.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-sleuth       | 1.3.5.RELEASE  | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-stream       | Ditmars.SR4    | Elmhurst.SR1  | Elmhurst.BUILD-SNAPSHOT |
| spring-cloud-zookeeper    | 1.2.2.RELEASE  | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT    |
| spring-boot               | 1.5.16.RELEASE | 2.0.6.RELEASE | 2.0.7.BUILD-SNAPSHOT    |
| spring-cloud-task         | 1.2.3.RELEASE  | 2.0.0.RELEASE | 2.0.1.BUILD-SNAPSHOT    |
| spring-cloud-vault        | 1.1.2.RELEASE  | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-gateway      | 1.0.2.RELEASE  | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-openfeign    |                | 2.0.2.RELEASE | 2.0.2.BUILD-SNAPSHOT    |
| spring-cloud-function     | 1.0.1.RELEASE  | 1.0.0.RELEASE | 1.0.1.BUILD-SNAPSHOT    |

注意：

SpringCloud 版本为 Edgware 及以下，eureka包改为：

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

SpringCloud 版本为 Edgware 以上，eureka包改为netflix：

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

### SpringCloudEureka

#### 入门案例（一） Server与Client

#### 入门案例（二）Server、Porvider与Consumer

**项目整体结构：**

![1548589316026](/files/rPT6uJCgd5xZBN4CfAOC)

**eureka-server入门**

**一、导入jar**

```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>

    <artifactId>lemon-soa</artifactId>
    <packaging>jar</packaging>

    <name>spring-cloud-eureka-server</name>

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

    <properties>
        <spring-cloud.version>Dalston.SR4</spring-cloud.version>
    </properties>

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

    <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>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

```

**二、建立启动类**

```java
package com.lemon.eureka.server;

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

/**
 * @author sjp
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApplication {

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

}
```

**三、配置yml**

```yml
server:
    port: 9001

eureka:
    instance:
        hostname: eureka-service
    client:
        # 不注册自己
        register-with-eureka: false
        # 获取服务
        fetch-registry: false
        # 注册中心地址
        service-url:
            defaultZone: http://localhost:${server.port}/eureka/

```

**四、访问**

<http://localhost:9001/>

![1548158001871](/files/mlx8CPaDFYBv5hQ3XXP2)

**eureka-api 入门**

**Tips**:此部分属于provider和consumer公用部分，所以单独作为一个模块，打包成jar供provider和consumer使用

**模块结构**

![1548340246457](/files/MYnYatcajpg32FDCQF2g)

**一、导入jar**

```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>

    <artifactId>eureka-api</artifactId>

</project>

```

**二、建立相关类**

```java
package com.lemon.soa.api;

public interface VideoService {
   /**
    * 获取视频信息
    * @param videoId 视频id
    * @return 视频信息
    */
   double getVideo(long videoId);
}
```

**eureka-provider入门**

**Tips**: Eureka本身只区分server和client(client有provider和consumer)，通过不同的配置来告知client，本身是provider还是consumer.

**模块结构**

![1548340282069](/files/NbOlFgWGerF94wURcIrf)

**一、导入jar**

```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>

    <artifactId>eureka-provider</artifactId>

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

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

    <dependencies>

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

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

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

        <!--内部依赖-->
        <dependency>
            <groupId>com.lemon</groupId>
            <artifactId>eureka-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

    </dependencies>

    <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>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

```

**二、建立相关类**

启动类：

```java
package com.lemon;

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

@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication {

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

}
```

服务接口实现：

```java
package com.lemon.api.impl;

import org.springframework.stereotype.Service;

import com.lemon.soa.api.VideoService;

/**
 * @author sjp
 * @date 2019/1/24
 **/
@Service
public class VideoServiceImpl implements VideoService {
   @Override
   public double getVideo(long videoId) {
      return Math.random();
   }
}
```

暴露服务：

```java
package com.lemon.controller;

import com.lemon.soa.api.VideoService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

@RestController
public class VideoController {

   @Resource
   private VideoService videoService;

   @RequestMapping(value = "/{videoId}", method = RequestMethod.GET)
   public Double getVideo(@PathVariable long videoId) {
      return videoService.getVideo(videoId);
   }
}
```

**三、配置yml**

```yml
server:
    port: 9002

spring:
    application:
        name: eureka-provider

eureka:
    instance:
        #使用ip进行注册
        prefer-ip-address: true
    client:
        serviceUrl:
            defaultZone: http://localhost:9001/eureka/
```

**四、访问**

<http://localhost:9001/>

![1548331878651](/files/VcbTuOEzO0JaS9XsxlUc)

**eureka-consumer入门**

**模块结构**

![1548340368984](/files/yIjOg89E4PHLyPbQHGcH)

**一、导入jar**

```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>

    <artifactId>eureka-consumer</artifactId>

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

    <properties>
        <spring-cloud.version>Edgware.SR3</spring-cloud.version>
    </properties>

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

    <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>

</project>

```

**二、建立相关类**

启动类：

```java
package com.lemon.consumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

/**
 * @author sjp
 * @date 2019/1/24
 **/
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaConsumerApplication {

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

	/**
	 * 启用负载均衡，默认算法是轮询
	 */
	@LoadBalanced
	@Bean
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}
```

调用服务：

```java
package com.lemon.consumer.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @author sjp
 * @date 2019/1/24
 **/
@RestController
public class ConsumerController {

   @Resource
   private RestTemplate restTemplate;

   @RequestMapping("/")
   public Double index() {
        return restTemplate.getForObject("http://eureka-provider/1", Double.class);
   }
}
```

**三、配置yml**

```yml
server:
    port: 9003

spring:
    application:
        name: eureka-consumer
eureka:
    instance:
        # 使用IP注册
        prefer-ip-address: true
    #注册地址
    client:
        service-url:
            defaultZone: http://localhost:9001/eureka/
```

**四、访问**

<http://localhost:9001/>

![1548339679969](/files/5KKQZRjtz5KCyOnVtTmR)

#### 熟悉掌握

**eureka-server配置详解**

| 参数名                                                   | 默认值                   | 备注                                                                                   |
| ----------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------ |
| enable-self-preservation                              | true                  | 自我保护模式，当出现出现网络分区、eureka在短时间内丢失过多客户端时，会进入自我保护模式，即一个服务长时间没有发送心跳，eureka 也不会将其删除，默认为true |
| eviction-interval-timer-in-ms                         | 60000                 | eureka server清理无效节点的时间间隔，默认60000毫秒，即60秒                                              |
| a-s-g-cache-expiry-timeout-ms                         | 6000                  | 缓存ASG信息的到期时间，单位为毫秒，默认为10 \* 60 \* 1000                                               |
| a-s-g-query-timeout-ms                                | 300                   | 查询AWS上ASG（自动缩放组）信息的超时值，单位为毫秒，默认为300                                                  |
| a-s-g-update-interval-ms                              | 5 \* 60 \* 1000       | 从AWS上更新ASG信息的时间间隔，单位为毫秒                                                              |
| a-w-s-access-id                                       |                       | 获取aws访问的id，主要用于弹性ip绑定，此配置是用于aws上的                                                    |
| a-w-s-secret-key                                      |                       | 获取aws私有秘钥，主要用于弹性ip绑定，此配置是用于aws上的                                                     |
| batch-replication                                     | false                 | 表示集群节点之间的复制是否为了网络效率而进行批处理                                                            |
| binding-strategy                                      |                       | 获取配置绑定EIP或Route53的策略                                                                 |
| delta-retention-timer-interval-in-ms                  | 30 \* 1000            | 清理任务程序被唤醒的时间间隔，清理过期的增量信息，单位为毫秒                                                       |
| disable-delta                                         | false                 | 增量信息是否可以提供给客户端看，默认为false                                                             |
| disable-delta-for-remote-regions                      | false                 | 增量信息是否可以提供给客户端或一些远程地区                                                                |
| disable-transparent-fallback-to-other-region          | false                 | 如果在远程区域本地没有实例运行，对于应用程序回退的旧行为是否被禁用                                                    |
| e-i-p-bind-rebind-retries                             | 3                     | 获取服务器尝试绑定到候选的EIP的次数                                                                  |
| e-i-p-binding-retry-interval-ms-when-unbound          | 1 \* 60 \* 1000       | 服务器检查ip绑定的时间间隔，单位为毫秒                                                                 |
| e-i-p-binding-retry-interval-ms                       | 5 \* 60 \* 1000       | 与上面的是同一作用，仅仅是稳定状态检查                                                                  |
| enable-replicated-request-compression                 | false                 | 复制的数据在发送请求时是否被压缩                                                                     |
| g-zip-content-from-remote-region                      | true                  | eureka服务器中获取的内容是否在远程地区被压缩，默认为true                                                    |
| json-codec-name                                       |                       | 如果没有设置默认的编解码器将使用全JSON编解码器，获取的是编码器的类名称                                                |
| list-auto-scaling-groups-role-name                    | ListAutoScalingGroups | 用来描述从AWS第三账户的自动缩放组中的角色名称                                                             |
| log-identity-headers                                  | true                  | Eureka服务器是否应该登录clientAuthHeaders                                                     |
| max-elements-in-peer-replication-pool                 | 10000                 | 复制池备份复制事件的最大数量                                                                       |
| max-elements-in-status-replication-pool:              | 10000                 | 可允许的状态复制池备份复制事件的最大数量                                                                 |
| max-idle-thread-age-in-minutes-for-peer-replication   | 10                    | 状态复制线程可以保持存活的空闲时间                                                                    |
| min-threads-for-status-replication                    | 1                     | 被用于状态复制的线程的最小数目                                                                      |
| max-idle-thread-in-minutes-age-for-status-replication | 15                    | 复制线程可以保持存活的空闲时间,默认为15分钟                                                              |
| max-threads-for-peer-replication                      | 20                    | 获取将被用于复制线程的最大数目                                                                      |
| max-time-for-replication                              | 30000                 | 尝试在丢弃复制事件之前进行复制的时间，默认为30000毫秒                                                        |
| min-threads-for-peer-replication                      | 5                     | 获取将被用于复制线程的最小数目                                                                      |
| number-of-replication-retries                         | 5                     | 获取集群里服务器尝试复制数据的次数                                                                    |
| peer-eureka-nodes-update-interval-ms                  | 10 \* 60 \* 1000      | 集群里eureka节点的变化信息更新的时间间隔，单位为毫秒                                                        |
| peer-eureka-status-refresh-time-interval-ms           | 30 \* 1000            | 服务器节点的状态信息被更新的时间间隔，单位为毫秒                                                             |
| peer-node-connect-timeout-ms                          | 200                   | 连接对等节点服务器复制的超时的时间，单位为毫秒                                                              |
| peer-node-read-timeout-ms                             | 200                   | 读取对等节点服务器复制的超时的时间，单位为毫秒                                                              |
| peer-node-total-connections                           | 1000                  | 获取对等节点上http连接的总数                                                                     |
| peer-node-connection-idle-timeout-seconds             | 30                    | http连接被清理之后服务器的空闲时间，默认为30秒                                                           |
| peer-node-total-connections-per-host                  | 500                   | 获取特定的对等节点上http连接的总数                                                                  |
| prime-aws-replica-connections                         | true                  | 对集群中服务器节点的连接是否应该准备                                                                   |
| rate-limiter-enabled                                  |                       | 限流是否应启用或禁用，默认为false                                                                  |
| rate-limiter-burst-size                               |                       | 速率限制的burst size ，默认为10，这里用的是令牌桶算法                                                    |
| rate-limiter-full-fetch-average-rate                  | 100                   | 速率限制器用的是令牌桶算法，此配置指定平均执行请求速率，默认为100                                                   |
| rate-limiter-privileged-clients                       |                       | 认证的客户端列表，这里是除了标准的eureka Java客户端。                                                     |
| rate-limiter-registry-fetch-average-rate              | 500                   | 速率限制器用的是令牌桶算法，此配置指定平均执行注册请求速率，默认为500                                                 |
| rate-limiter-throttle-standard-clients                | false                 | 是否对标准客户端进行限流，默认false                                                                 |
| registry-sync-retries                                 | 5                     | 当eureka服务器启动时尝试去获取集群里其他服务器上的注册信息的次数，默认为5                                             |
| registry-sync-retry-wait-ms                           | 30 \* 1000            | 当eureka服务器启动时获取其他服务器的注册信息失败时，会再次尝试获取，期间需要等待的时间，默认为30 \* 1000毫秒                       |
| remote-region-app-whitelist                           |                       | 必须通过远程区域中检索的应用程序的列表                                                                  |
| remote-region-connect-timeout-ms                      | 1000                  | 连接到对等远程地eureka节点的超时时间，默认为1000毫秒                                                      |
| remote-region-connection-idle-timeout-seconds         | 30                    | http连接被清理之后远程地区服务器的空闲时间，默认为30秒                                                       |
| remote-region-fetch-thread-pool-size                  | 20                    | 用于执行远程区域注册表请求的线程池的大小，默认为20                                                           |
| remote-region-read-timeout-ms                         | 1000                  | 获取从远程地区eureka节点读取信息的超时时间，默认为1000毫秒                                                   |
| remote-region-registry-fetch-interval                 | 30                    | 从远程区域取出该注册表的信息的时间间隔，默认为30秒                                                           |
| remote-region-total-connections                       | 1000                  | 获取远程地区对等节点上http连接的总数，默认为1000                                                         |
| remote-region-total-connections-per-host              | 500                   | 获取远程地区特定的对等节点上http连接的总数，默认为500                                                       |
| remote-region-trust-store                             |                       | 用来合格请求远程区域注册表的信任存储文件，默认为空                                                            |
| remote-region-trust-store-password                    |                       | 获取偏远地区信任存储文件的密码，默认为“changeit”                                                        |
| remote-region-urls                                    |                       | 远程地区的URL列表                                                                           |
| remote-region-urls-with-name                          |                       | 针对远程地区发现的网址域名的map                                                                    |
| renewal-percent-threshold                             | 0.85                  | 阈值因子，默认是0.85，如果阈值比最小值大，则自我保护模式开启                                                     |
| renewal-threshold-update-interval-ms                  | 15 \* 60 \* 1000      | 阈值更新的时间间隔，单位为毫秒                                                                      |
| response-cache-auto-expiration-in-seconds             | 180                   | 当注册表信息被改变时，则其被保存在缓存中不失效的时间，默认为180秒                                                   |
| response-cache-update-interval-ms                     | 30 \* 1000            | 客户端的有效负载缓存应该更新的时间间隔，默认为30 \* 1000毫秒                                                  |
| retention-time-in-m-s-in-delta-queue                  | 3 \* 60 \* 1000       | 客户端保持增量信息缓存的时间，从而保证不会丢失这些信息，单位为毫秒                                                    |
| route53-bind-rebind-retries                           | 3                     | 服务器尝试绑定到候选Route53域的次数                                                                |
| route53-binding-retry-interval-ms                     | 5 \* 60 \* 1000       | 服务器应该检查是否和Route53域绑定的时间间隔，默认为5 \* 60 \* 1000毫秒                                       |
| route53-domain-t-t-l                                  | 301                   | 用于建立route53域的ttl，默认为301                                                              |
| sync-when-timestamp-differs                           | true                  | 当时间变化实例是否跟着同步，默认为true                                                                |
| use-read-only-response-cache                          | true                  | 目前采用的是二级缓存策略，一个是读写高速缓存过期策略，另一个没有过期只有只读缓存，默认为true，表示只读缓存                              |
| wait-time-in-ms-when-sync-empty                       | 1000 \* 60 \* 5       | 在Eureka服务器获取不到集群里对等服务器上的实例时，需要等待的时间，单位为毫秒，默认为1000 \* 60 \* 5                         |
| xml-codec-name                                        |                       | 如果没有设置默认的编解码器将使用xml编解码器，获取的是编码器的类名称                                                  |

### SpringCloudFegin

官方文档：<https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.0.2.RELEASE/single/spring-cloud-openfeign.html>

**一、导入jar**

Springboot 2.0.0 以下

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

Springboot 2.0.0 及以上

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

**二、建立相关类**

启动类(加上注解)：

```java
/**
  * 如果为了把eureka共有接口抽成单独模块，需注明扫描包，才可以加载jar包中的@FeignClient
  * @EnableFeignClients(basePackages = { "com.lemon.soa.api" })
  */
@EnableFeignClients
```

修改类：

```java
package com.lemon.soa.api;

// 其中eureka-provider是提供服务者的应用名，即eureka-provider的应用名
@FeignClient(name = "eureka-provider")
public interface VideoService {
   /**
    * 获取视频信息
    * @param videoId 视频id
    * @return 视频信息
    */
   @GetMapping(value = "/{videoId}")
   double getVideo(long videoId);
}
```

调用服务：

```java
package com.lemon.consumer.controller;

import com.lemon.soa.api.dto.CategoryDTO;
import com.lemon.soa.api.provider.CategoryProvider;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.List;

/**
 * @author sjp
 * @date 2019/1/24
 **/
@RestController
public class ConsumerController {
 
	/**
	 * feign 方式
	 */
	@Resource
	private CategoryProvider categoryProvider;

	@GetMapping(value = "/category")
	public List<CategoryDTO> getCategoryTree() {
		return categoryProvider.getCategoryTree();
	}

}

```

**三、配置yml**

```yml
server:
    port: 9003

spring:
    application:
        name: eureka-consumer
eureka:
    instance:
        # 使用IP注册
        prefer-ip-address: true
    #注册地址
    client:
        service-url:
            defaultZone: http://localhost:9001/eureka/
```

**四、访问**

<http://localhost:9001/>

![1548339679969](/files/5KKQZRjtz5KCyOnVtTmR)

坑：

问题一：

有些公共的组件抽出来其他模块的maven依赖，此时要在使用的项目中加载此jar包的spring component以及feign组件，仅仅依靠@ComponentScan是不够的，还需要在@EnableFeignClients(basePackages = {"com.xixicat"})中标注basekPackages。

问题二：

使用@FeignClient注解，要求name不重复，否则Bean会被覆盖，或者无法启动。这是Feign的一个缺点吧。

推荐修复方案：

```yml
spring:

    # 允许重复名称的bean定义，为了解决Fegin重复命名无法启动的问题
    main:
        allow-bean-definition-overriding: true
```

其他修复方案(手动初始化Feign代理的类)：

```java
package com.lemon.consumer.controller;

import com.lemon.soa.api.dto.CategoryDTO;
import com.lemon.soa.api.dto.VideoDTO;
import com.lemon.soa.api.provider.CategoryProvider;
import com.lemon.soa.api.provider.VideoProvider;
import feign.Client;
import feign.Contract;
import feign.Feign;
import feign.Logger;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.slf4j.Slf4jLogger;
import org.springframework.cloud.openfeign.FeignClientsConfiguration;
import org.springframework.context.annotation.Import;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * FeginMutiNameController Fegin的一个缺陷，feginName不可以重复定义（除set allow-bean-definition-overriding: true的第二种方案）
 * @author sjp
 * @date 2019/12/15
 */
@RestController
@Import(FeignClientsConfiguration.class)
public class FeginMutiNameController {

	private VideoProvider		videoProvider;
	private CategoryProvider	categoryProvider;

	public FeginMutiNameController(Decoder decoder, Encoder encoder, Client client, Contract contract) {
		this.videoProvider = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract)
				// 默认是Logger.NoOpLogger
				.logger(new Slf4jLogger(VideoProvider.class))
				// 默认是Logger.Level.NONE
				.logLevel(Logger.Level.FULL).target(VideoProvider.class, "http://provider");

		this.categoryProvider = Feign.builder().client(client).encoder(encoder).decoder(decoder).contract(contract)
				// 默认是Logger.NoOpLogger
				.logger(new Slf4jLogger(CategoryProvider.class))
				// 默认是Logger.Level.NONE
				.logLevel(Logger.Level.FULL).target(CategoryProvider.class, "http://provider");
	}

	@GetMapping(value = "/test1")
	public List<CategoryDTO> getCategoryTree() {
		return categoryProvider.getCategoryTree();
	}

	@GetMapping(value = "/test2/{id}")
	public VideoDTO index(@PathVariable(value = "id") Long id) {
		return videoProvider.getVideo(id);
	}

}
```

### SpringCloud使用Config作为配置中心

#### 一、介绍

​ 服务端：配置中心

​ 客户端：接受配置的应用

#### 二、配置

**1、Server端配置**

**A、pom**

```pom
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

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

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

  <!-- 添加spring-boot的maven插件 -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
```

**B、yml**

```yml
server:
    port: 9000
spring:
    application:
        name: lemon-config-server
    cloud:
        config:
            server:
                git:
                	# SpringCloud Config 的配置是放在git上的
                    uri: https://github.com/ATSJP/lemon-config
                    # 指定搜索根路径下的所有目录，若有多个路径使用逗号隔开
                    search-paths: /**  
```

**C、Application**

```java
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

/**
 * @author sjp
 */
@EnableConfigServer
@SpringBootApplication
public class LemonConfigApplication {

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

}
```

全部配置好后，启动应用，访问 <http://localhost:9000/admin/dev> （<http://localhost:9000/admin-dev.json，http://localhost:9000/admin-dev.properties）>

![1561601935481](/files/JJbykIaiFViMVGkcuiga)

注：配置文件的访问规则如下：

```
/{name}-{profiles}.yml
/{label}/{name}-{profiles}.yml

name : 文件名，一般以服务名来命名
profiles : 一般作为环境标识
lable : 分支（branch），指定访问某分支下的配置文件

例如：http://localhost:9000/dv_lemon_2019_07/provider-dev.yml
```

有一点值得注意的是，如果有两个前缀名相同文件，例如一个order.yml，一个order-dev.yml。那么在访问相同前缀的文件时，config-server会对这两个文件进行一个合并。例如order.yml有一段配置是order-dev.yml没有的，理应访问order-dev.yml的时候是没有那段配置的，但访问的结果却是它俩合并之后的内容，即order-dev.yml会拥有order.yml里所配置的内容。

**2、Client端配置**

**A、pom**

```pom
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

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

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- 实现Config的客户端配置 -->
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <!-- 实现通过端点refresh手动刷新 -->
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-actuator</artifactId>
    </dependency>
  </dependencies>
  
  <!-- 添加spring-boot的maven插件 -->
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
```

**B、yml**

1. bootstrap.yml

```yml
# 对应着config server所获取配置文件的{application}和URL
spring:
    application:
        name: admin
    cloud:
        config:
            uri: http://localhost:9000/
            # 对应着文件后面的后缀{profile}
            profile: dev
            # 分支
            label: master
```

2. application.yml

```yml
version-config: ${version}
```

**C、Application**

```java
@SpringBootApplication
public class LemonAdminApplication {

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

}
```

**D、Controller**

```java
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@Controller
@RestController
public class LoginController {

    @Value("${version-config}")
    private String version;

    @GetMapping("/test")
    public String getVersion() {
        return this.version;
    }
    
}
```

#### 三、踩坑


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://atsjp.gitbook.io/note/java/spring/springboot-and-springcloud/springcloud-xi-lie.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
