SpringCloud

概念

微服务架构的演进思路

多服务应用->微服务应用(单服务应用+服务通信(restful))

问题:每个服务的访问路径需要硬编码

微服务应用+服务中心

问题:每次访问需要手动遍历,当同一服务存在多个实例时进一步出现负载均衡问题

多实例微服务应用+服务中心+负载均衡器

问题:

当某个服务故障时可能造成连锁反应,产生雪崩

所有服务都面向外部可用,缺少统一访问控制

如何采用类似rpc的接口调用风格

应用如此之多,每个应用都要单独编写一套配置,如何集中管理配置

等等

根据以上思路,微服务的核心组件呼之欲出:服务中心、负载均衡、熔断降级、服务网关、配置中心

核心组件

功能 介绍 组件
服务中心 服务注册和服务发现 ZooKeeper、Eureka、Nacos、Consul
负载均衡 负载均衡和服务映射 Ribbon、LoadBalancer
熔断降级 服务熔断、服务降级、流量限制 Hystrix、Resilience4j、Sentinel
服务网关 服务映射、过滤控制 Zuul、Gateway、Kong
配置中心 集中配置、远端配置 Config、Nacos、Consul
接口风格 支持 RPC 风格调用 Feign、OpenFeign
事务管理 分布式事务协调 Seata
监控预警 实时监控系统指标,异常告警 Prometheus 、Micrometer
服务追踪 分布式链路追踪,定位请求延迟、性能瓶颈 Zipkin、Jaeger

服务中心

服务中心的核心本质是一个单独维护的服务列表,服务上线时通过心跳包机制进行把自身添加到服务列表中,服务自身也可以获取这个服务列表

实现集群比较复杂,各类型的服务中心基于不同策略(侧重点)采用不同的实现

负载均衡

负载均衡器的核心本质是根据服务名称service-id查询服务列表,获取对应的服务实例集合,根据某种均衡策略获取其中一个服务实例,返回这个实例对应的 ip 地址

熔断降级

熔断降级的核心本质是根据一定的策略对原始方法(类)进行代理,当发生意外时根据策略调用指定的方法或者触发指定的行为

服务网关

服务网关的核心本质是借助过滤器对请求进行拦截(其中会发生负载均衡)处理

配置中心

配置中心的核心本质是把分散的配置文件进行集中化、云端化管理

功能列表

功能 介绍 常见组件
服务注册(Service Registration) 微服务启动时向注册中心注册自身信息(如IP、端口等),以便其他服务发现并调用 Eureka, Nacos, Consul, ZooKeeper
服务发现(Service Discovery) 客户端或网关根据服务名动态获取可用服务实例列表,实现去硬编码的服务调用 Ribbon, Spring Cloud LoadBalancer, Envoy
负载均衡(Load Balancing) 在多个服务实例之间分配请求,提高系统吞吐量和可用性 Ribbon, Spring Cloud Gateway, Nginx, HAProxy, Envoy
限流 & 熔断(Rate Limiting & Circuit Breaking) 控制流量防止过载,服务故障时快速失败避免雪崩 Hystrix(已弃用), Resilience4j, Sentinel, Istio
服务网关(API Gateway) 统一入口,处理路由、鉴权、限流、日志记录等功能 Spring Cloud Gateway, Zuul, Kong, Traefik
配置管理(Configuration Management) 集中管理各服务的配置信息,支持动态更新 Spring Cloud Config, Nacos Config, Consul KV Store
分布式事务(Distributed Transactions) 跨服务操作保持数据一致性 Seata, RocketMQ事务消息, Saga模式, TCC模式
服务追踪(Distributed Tracing) 跟踪请求链路,定位性能瓶颈和故障点 Zipkin, Jaeger, SkyWalking, Pinpoint
监控与告警(Monitoring & Alerting) 实时监控系统状态,异常时触发告警 Prometheus + Grafana, ELK Stack, Zabbix
认证与授权(Authentication & Authorization) 控制访问权限,保障系统安全 OAuth2, JWT, OpenID Connect, Keycloak, Auth0
消息队列(Message Queue) 实现异步通信、解耦服务、削峰填谷 Kafka, RabbitMQ, RocketMQ, ActiveMQ
缓存(Caching) 提高数据读取速度,降低后端压力 Redis, Memcached, Caffeine, Hazelcast
弹性设计(Resilience Design) 构建具备容错、自动恢复能力的系统 Retry, Timeout, Bulkhead, Fallback 模式
日志聚合(Log Aggregation) 收集所有服务的日志,便于统一分析 ELK Stack (Elasticsearch + Logstash + Kibana), Fluentd
持续集成 / 持续部署(CI/CD) 自动化构建、测试、部署流程,提升交付效率 Jenkins, GitLab CI/CD, ArgoCD, Tekton
容器编排(Container Orchestration) 管理容器生命周期、调度、扩缩容 Kubernetes, Docker Swarm, Mesos
服务网格(Service Mesh) 将网络通信、熔断、限流等交给基础设施层统一管理 Istio, Linkerd, Consul Connect

SpringCloud Netflix

功能 解决方案 组件
服务注册与发现 提供服务注册中心,支持服务自动注册和发现 Eureka
负载均衡 客户端负载均衡器,支持多种负载均衡策略 Ribbon
声明式 REST 调用 简化 HTTP 请求调用,支持负载均衡 Feign
断路器(熔断) 实现服务降级、限流、熔断等功能 Hystrix (已停止维护,推荐使用 Resilience4j)
API 网关 提供统一入口,支持路由、过滤等功能 Zuul (已停止维护,推荐使用 Spring Cloud Gateway)
配置管理 集中管理外部配置 Spring Cloud Config
分布式追踪 跟踪请求链路,分析性能瓶颈 Sleuth + Zipkin
消息总线 实现配置刷新通知等功能 Spring Cloud Bus
  • 服务注册与发现:通过 Eureka Server 注册服务实例,客户端使用 @EnableDiscoveryClient 注解自动发现服务。
  • 负载均衡:Ribbon 默认集成在 Feign 中,通过 @FeignClient 自动实现负载均衡调用。
  • 声明式 REST 调用:使用 @FeignClient 定义接口,结合 Ribbon 实现负载均衡。
  • 断路器:使用 @HystrixCommand 注解定义熔断逻辑,或者使用 Resilience4j 替代 Hystrix。
  • API 网关:Zuul 或者 Spring Cloud Gateway 作为 API 网关,处理路由、过滤等功能。
  • 配置管理:Spring Cloud Config Server 存储集中配置,客户端通过 @Value@ConfigurationProperties 注解获取配置。

SpringCloud Alibaba

功能 解决方案 组件
服务注册与发现 提供服务注册中心,支持服务自动注册和发现 Nacos
负载均衡 客户端负载均衡器,支持多种负载均衡策略 Spring Cloud LoadBalancer (默认)
声明式 REST 调用 简化 HTTP 请求调用,支持负载均衡 OpenFeign
限流 & 熔断 实现服务降级、限流、熔断等功能 Sentinel
API 网关 提供统一入口,支持路由、过滤等功能 Sentinel-Dubbo, Spring Cloud Gateway
配置管理 集中管理外部配置 Nacos Config
分布式追踪 跟踪请求链路,分析性能瓶颈 SkyWalking, Apache APISIX
消息队列 支持异步通信、削峰填谷 RocketMQ
分布式事务 支持跨服务的数据一致性 Seata
  • 服务注册与发现:通过 Nacos Server 注册服务实例,客户端使用 @EnableDiscoveryClient 注解自动发现服务。
  • 负载均衡:Spring Cloud LoadBalancer 作为默认负载均衡器,OpenFeign 集成 LoadBalancer 实现负载均衡调用。
  • 声明式 REST 调用:使用 @FeignClient 定义接口,结合 LoadBalancer 实现负载均衡。
  • 限流 & 熔断:Sentinel 提供流量控制、熔断降级功能,使用 @SentinelResource 注解定义资源点,配置限流规则。
  • API 网关:可以使用 Spring Cloud Gateway 结合 Sentinel 实现网关层的限流和熔断保护。
  • 配置管理:Nacos Config Server 存储集中配置,客户端通过 @RefreshScope 注解动态刷新配置。
  • 分布式追踪:SkyWalking 可以集成到 Spring Cloud Alibaba 中,用于跟踪请求链路。
  • 消息队列:RocketMQ 作为高性能的消息队列,支持异步通信、削峰填谷。

SpringCloud NetFlix

创建项目

<dependencyManagement>
    <dependencies>
        <!-- spring-boot 依赖版本控制 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.1.4.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!-- spring-cloud 依赖版本控制 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Greenwich.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

多模块项目,后续模块均作为该项目的子模块

Eureka

自我保护机制

Eureka通过心跳包确定服务是否正常,但在网络故障时,有可能服务正常但无法接收服务实例的心跳,此时不应该立即注销该服务实例,而是保留服务等待网络恢复正常,这就是自我保护机制

假定存在100个注册的微服务,某一时刻A,只有80个心跳包成功响应,此时eureka会进入自我保护机制,即使连续多次都只有80个心跳包响应,也不会移除未响应的服务;某一时刻B,有90个心跳包响应,此时eureka退出自我保护机制,未响应的10个服务会根据上次响应时间和当前时间的差值判断是否清除,即如果这10个服务已经连续3次未响应就被清除(即自我保护期间的时间会被累积)

宁可保留所有服务,也不盲目注销任何服务

通过 eureka.server.enable-self-preservation=false 可以关闭自我保护机制

为什么说它是AP原则?

因为它基于自我保护机制和过期清理策略,不能严格保证服务列表中的服务全部都是最新可用状态,而是允许服务不可用,这避免了因网络分区故障造成的误清理,从而提高可用性,此外自我保护机制本身就是保证分区容错性的。

由于服务状态不是最新的(注册中心的服务状态和实际服务状态不一致),实际部分服务可能调用失败(自动重试机制在一定程度解决了这个问题),这牺牲了强一致性(随着时间推移网络故障恢复,实际最终还是一致的)

简单示例

server

载入依赖

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

配置文件

spring:
  application:
    # 应用(服务)的逻辑名称, 微服务架构中标识在注册中心的注册名称
    name: eureka-server
server:
  port: 7000

eureka:
  instance:
    # 应用(服务)通常不会单例部署, 而是同一服务具有多个实例, 该属性用于区分同一服务的不同实例
    instance-id: eureka-server-single
    # 当前服务的位置, 可以是localhost、ip、dns域名
    hostname: localhost
  client:
    # 是否注册自己到服务中心, 此处本身就是注册中心, 因此是不把自己注册到自己
    register-with-eureka: false
    # 是否抓取服务注册列表, 通常注册中心本身不抓取, 而是服务从注册中心抓取
    fetch-registry: false

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的服务器, 即注册中心
@EnableEurekaServer
public class EurekaServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

provider

载入依赖

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

配置文件

spring:
  application:
    name: eureka-provider
server:
  port: 8000

eureka:
  instance:
    instance-id: eureka-provider-single
  client:
    # 该服务作为纯粹的提供者, 无需获取服务列表
    fetch-registry: false
    service-url:
      # 注册中心位置
      defaultZone: http://localhost:7000/eureka/

控制器

package xyz.ssydx.springcloud.controller;

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

@RestController
public class MyController {

    @RequestMapping("/dc")
    public String dc() {
        return "serviceId: " + "eureka-provider" + ", instanceId: " + "eureka-provider-single";
    }
}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务
@EnableEurekaClient
public class EurekaProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaProviderApplication.class, args);
    }
}

consumer

载入依赖

同provider模块

配置文件

spring:
  application:
    name: eureka-consumer
server:
  port: 9000

eureka:
  instance:
    instance-id: eureka-consumer-single
  client:
    # 该服务作为纯粹的消费者, 无需注册到注册中心
    register-with-eureka: false
    service-url:
      # 注册中心位置
      defaultZone: http://localhost:7000/eureka/

配置类

package xyz.ssydx.springcloud.config;

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

@Configuration
public class ConfigBean {
    @Bean
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

控制器

package xyz.ssydx.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class MyController {
    @Autowired
    // 获取服务列表
    private DiscoveryClient client;
    @Autowired
    // Restful
    private RestTemplate restTemplate;

    @RequestMapping("/dc")
    public String dc() {
        String serviceId = client.getServices().get(0);
        ServiceInstance serviceInstance = client.getInstances(serviceId).get(0);
        return restTemplate.getForObject(serviceInstance.getUri() + "/dc", String.class);
    }
}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务, 此处等价于 @EnableEurekaClient, 它同时也适用于其他注册中心
@EnableDiscoveryClient
public class EurekaConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumerApplication.class, args);
    }
}

思考

每次调用服务都要自行遍历服务列表选择对应的服务,进而获取对应的服务实例,再找到服务实例所在地址,最后才能访问,这很不方便,有没有更简单的方法?

生产环境中无论是注册中心还是服务实例都不是单一存在的,而是多个注册中心组成集群,多个服务实例组成多实例服务,从而保证服务的高可用性,此时调用方调用服务时势必要经过某种策略选择注册中心,进而又根据某种策略选择某个服务实例,这就是负载均衡,如何实现?

以上两个问题将由ribbon这一组件解决

Ribbon

核心作用是:根据服务名选择服务,并根据负载均衡算法选择服务实例,调用失败后尝试下一可用服务实例

即:服务发现、负载均衡、故障转移

什么时候主机名被视为服务名?

发起请求:
URL → http://host/path

↓

是否使用 @LoadBalanced 的客户端?
└─ 否 → 直接发起 HTTP 请求(不走服务发现)
└─ 是 → 继续判断

↓

host 是否是合法 IP 或域名?
└─ 是 → 直接发起 HTTP 请求(跳过服务发现)
└─ 否 → 继续判断

↓

尝试将 host 视为服务名,去服务注册中心查找实例:
└─ 找到多个实例 → 根据负载均衡策略选一个
└─ 找不到实例 → 抛出 UnknownHostException 或 ServiceInstanceNotFoundException

↓

替换 host 为真实 IP:PORT,发起最终 HTTP 请求

protocal://host[:port]/path/to?var1=value1&var2=value2 中的 host 判断

检查项 条件 是否跳过服务发现
host 是 IPv4 地址 192.168.1.10 ✅ 跳过
host 是 IPv6 地址 [::1]fe80::1 ✅ 跳过
host 是 localhost127.0.0.1 本地地址 ✅ 跳过
host 是域名(DNS 可解析) www.example.com ✅ 跳过
host 是数字开头的字符串 123abc.com(不合法域名) ❌ 不跳过,尝试作为服务名处理

简单示例

server

在 C:Windows/System32/drivers/etc/host中添加

127.0.0.1 eureka7001.com 127.0.0.1 eureka7002.com 127.0.0.1 eureka7003.com

模拟多服务器环境

载入依赖

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

编写配置

spring:
  application:
    # 应用(服务)的逻辑名称, 微服务架构中标识在注册中心的注册名称
    name: eureka-server
server:
  port: 7001

eureka:
  instance:
    # 应用(服务)通常不会单例部署, 而是同一服务具有多个实例, 该属性用于区分同一服务的不同实例
    instance-id: eureka-server-7001
    # 当前服务的位置, 可以是localhost、ip、dns域名
    hostname: eureka7001.com
  client:
    # 是否注册自己到服务中心, 此处本身就是注册中心, 因此是不把自己注册到自己
    register-with-eureka: false
    # 是否抓取服务注册列表, 通常注册中心本身不抓取, 而是服务从注册中心抓取
    fetch-registry: false
    # 注册中心位置, 目的是构建集群
    service-url:
      defaultZone: http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的服务器, 即注册中心
@EnableEurekaServer
public class EurekaServerApplication_7001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication_7001.class, args);
    }
}

同理创建 eureka-server-7002 eureka-server-7003 两个服务器,注意修改对应的配置属性

provider

载入依赖

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

编写配置

spring:
  application:
    name: eureka-provider
server:
  port: 8001

eureka:
  instance:
    instance-id: eureka-provider-8001
  client:
    # 该服务作为纯粹的提供者, 无需获取服务列表
    fetch-registry: false
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

控制器

package xyz.ssydx.springcloud.controller;

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

@RestController
public class MyController {

    @RequestMapping("/dc")
    public String dc() {
        return "serviceId: " + "eureka-provider" + ", instanceId: " + "eureka-provider-8001";
    }
}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务
@EnableEurekaClient
public class EurekaProviderApplication_8001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaProviderApplication_8001.class, args);
    }
}

同理创建 eureka-provider-8002 eureka-provider-8003

consumer

载入依赖

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

编写配置

spring:
  application:
    name: eureka-consumer
server:
  port: 9001

eureka:
  instance:
    instance-id: eureka-consumer-single
  client:
    # 该服务作为纯粹的消费者, 无需注册到注册中心
    register-with-eureka: false
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

配置类

package xyz.ssydx.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
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 ConfigBean {

    // 使用随机替代默认的轮询
    @Bean
    public IRule iRule() {
        return new RandomRule();
    }

    @Bean
    // 启用路径映射和负载均衡
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
}

控制器

package xyz.ssydx.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class MyController {
    @Autowired
    // Restful
    private RestTemplate restTemplate;

    // 此处直接使用服务名, template在请求前会根据服务列表查询出服务名对应的服务实例, 进而查询到服务实例所在的地址
    // 多实例情况会根据负载均衡策略进行实例的选择, 默认轮询, 可使用其他策略甚至自定义策略
    private final String prefix = "http://eureka-provider";

    @RequestMapping("/dc")
    public String dc() {
        return restTemplate.getForObject( prefix + "/dc", String.class);
    }
}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务, 此处等价于 @EnableEurekaClient, 它同时也适用于其他注册中心
@EnableDiscoveryClient
public class EurekaConsumerApplication_9001 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumerApplication_9001.class, args);
    }
}

不难看出,ribbon 主要解决了 服务名称到服务地址的映射、负载均衡两个重要问题

注意:此处的负载均衡仅指服务提供者的负载均衡,注册中心的负载均衡默认只有轮询这一种策略

Feign

本质上 feign 依然是 eureka+ribbon, 只是它提供了一种类似 rpc 调用风格

当消费者调用该某接口方法时会自动映射为访问 指定服务下的指定端点

简单示例

server

使用 ribbon 的示例

provider

使用 ribbon 的示例

consumer

载入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!-- 等价 -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-openfeign</artifactId>-->
<!--        </dependency>-->
    </dependencies>

编写配置

spring:
  application:
    name: eureka-consumer
server:
  port: 9002

eureka:
  instance:
    instance-id: eureka-consumer-single
  client:
    # 该服务作为纯粹的消费者, 无需注册到注册中心
    register-with-eureka: false
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

配置类

package xyz.ssydx.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConfigBean {

    // 使用随机替代默认的轮询
    @Bean
    public IRule iRule() {
        return new RandomRule();
    }

}

RPC风格接口

package xyz.ssydx.springcloud.rpc;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

// 指定服务名称
@FeignClient(name = "eureka-provider")
@Component
public interface MyRpc {
    // 接口到路径的映射
    @RequestMapping("/dc")
    String interface_dc();
}

控制器

package xyz.ssydx.springcloud.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.ssydx.springcloud.rpc.MyRpc;

@RestController
public class MyController {
    @Autowired
    private MyRpc myRpc;

    @RequestMapping("/dc")
    public String dc() {
        return myRpc.interface_dc();
    }
}

主启动类

package xyz.ssydx.springcloud;

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
// 作为 Eureka 的客户端, 即服务, 此处等价于 @EnableEurekaClient, 它同时也适用于其他注册中心
@EnableDiscoveryClient
// 扫描指定包下带有 @FeignClient 注解的接口, 便于进行动态代理, 从而实现 rpc 风格调用
@EnableFeignClients(basePackages = {"xyz.ssydx.springcloud.rpc"})
public class EurekaConsumerApplication_9002 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumerApplication_9002.class, args);
    }
}

Hystrix

主要用于服务降级、服务熔断、实时监控

简单示例

server

使用 ribbon 的示例

provider

载入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    </dependency>
</dependencies>

编写配置

spring:
  application:
    name: eureka-provider
server:
  port: 8004

eureka:
  instance:
    instance-id: eureka-provider-8004
  client:
    # 该服务作为纯粹的提供者, 无需获取服务列表
    fetch-registry: false
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

控制器

package xyz.ssydx.springcloud.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.TimeUnit;

// 提供者端降级
@RestController
public class MyController {

    @RequestMapping("/dc1")
    // 熔断机制的核心注解, 此处指定发生错误后的降级方法
    @HystrixCommand(fallbackMethod = "fallback")
    public String dc1() {
        if (true) throw new RuntimeException("error");
        return "serviceId: " + "eureka-provider" + ", instanceId: " + "eureka-provider-8004";
    }

    public String fallback() {
        return "error";
    }

    @RequestMapping("/dc2")
    public String dc2() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "serviceId: " + "eureka-provider" + ", instanceId: " + "eureka-provider-8004";
    }

    @RequestMapping("/dc3")
    public String dc3() {
        if (true) throw new RuntimeException("error");
        return "serviceId: " + "eureka-provider" + ", instanceId: " + "eureka-provider-8004";
    }
    @RequestMapping("/dc4")
    public String dc4() {
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return "serviceId: " + "eureka-provider" + ", instanceId: " + "eureka-provider-8004";
    }

}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务
@EnableEurekaClient
// 启用熔断器
@EnableCircuitBreaker
public class EurekaProviderApplication_8004 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaProviderApplication_8004.class, args);
    }
}

consumer

载入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
            <version>1.4.6.RELEASE</version>
        </dependency>
        <!-- 等价 -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-starter-openfeign</artifactId>-->
<!--        </dependency>-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

编写配置

spring:
  application:
    name: eureka-consumer
server:
  port: 9003

eureka:
  instance:
    instance-id: eureka-consumer-single
  client:
    # 该服务作为纯粹的消费者, 无需注册到注册中心
    register-with-eureka: false
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

配置类

package xyz.ssydx.springcloud.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ConfigBean {

    // 使用随机替代默认的轮询
    @Bean
    public IRule iRule() {
        return new RandomRule();
    }

}

RPC风格接口

package xyz.ssydx.springcloud.rpc;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

// 指定服务名称
@FeignClient(name = "eureka-provider")
@Component
public interface MyRpc {
    // 接口到路径的映射
    @RequestMapping("/dc1")
    String interface_dc1();

    // 接口到路径的映射
    @RequestMapping("/dc2")
    String interface_dc2();

    // 接口到路径的映射
    @RequestMapping("/dc3")
    String interface_dc3();

    // 接口到路径的映射
    @RequestMapping("/dc4")
    String interface_dc4();
}

控制器

package xyz.ssydx.springcloud.controller;

import com.netflix.hystrix.contrib.javanica.annotation.DefaultProperties;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import xyz.ssydx.springcloud.rpc.MyRpc;

// 消费者端降级
@RestController
// 全局降级方法(默认降级方法), 优先级低于方法层面的
@DefaultProperties(defaultFallback = "globalFallback", commandProperties = {
        @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
})
public class MyController {
    @Autowired
    private MyRpc myRpc;


    @RequestMapping("/dc1")
    public String dc1() {
        return myRpc.interface_dc1();
    }

    @RequestMapping("/dc2")
    @HystrixCommand(fallbackMethod = "fallback", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1500")
    })
    public String dc2() {
        return myRpc.interface_dc2();
    }

    public String fallback() {
        return "timeout";
    }

    @RequestMapping("/dc3")
    // 启用默认降级方法
    @HystrixCommand
    public String dc3() {
        return myRpc.interface_dc3();
    }

    @RequestMapping("/dc4")
    // 启用默认降级方法
    @HystrixCommand
    public String dc4() {
        return myRpc.interface_dc4();
    }

    public String globalFallback() {
        return "globalFallback";
    }

}

主启动类

package xyz.ssydx.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务, 此处等价于 @EnableEurekaClient, 它同时也适用于其他注册中心
@EnableDiscoveryClient
// 扫描指定包下带有 @FeignClient 注解的接口, 便于进行动态代理, 从而实现 rpc 风格调用
@EnableFeignClients(basePackages = {"xyz.ssydx.springcloud.rpc"})
// 启用熔断器
@EnableCircuitBreaker
public class EurekaConsumerApplication_9003 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumerApplication_9003.class, args);
    }
}

Dashboard示例

TODO

Zuul

主要功能是路由和过滤

简单示例

在实际生产中都会多实例(集群)部署,此处进行简化

在实际生产中还会结合 Feign、Hystrix等相关组件

server

使用 ribbon 的示例

provider

载入依赖

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

编写配置

spring:
  application:
    name: eureka-provider
server:
  port: 8006

eureka:
  instance:
    instance-id: eureka-provider-single
  client:
    # 该服务作为纯粹的提供者, 无需获取服务列表
    fetch-registry: false
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

控制器

package xyz.ssydx.springcloud.controller;

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

@RestController
public class MyController {

    @RequestMapping("/dc")
    public String dc() {
        return "serviceId: " + "eureka-provider" + ", instanceId: " + "eureka-provider-8006";
    }

}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务
@EnableEurekaClient
public class EurekaProviderApplication_8006 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaProviderApplication_8006.class, args);
    }
}

consumer-provider

载入依赖

同 provider

编写配置

spring:
  application:
    name: eureka-consumer-provider
server:
  port: 9006

eureka:
  instance:
    instance-id: eureka-consumer-provider-single
  client:
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

配置类

package xyz.ssydx.springcloud.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 ConfigBean {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

}

控制器

package xyz.ssydx.springcloud.controller;

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

@RestController
public class MyController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/dc")
    public String dc() {
        // 经过zuul
        // zuul 被 template 解析为 http://localhost:11000
        // 必须包含 /ssydx 前缀
        // 由于 eureka-provider 服务名称被忽略, 只能通过 /provider/** 访问
        return restTemplate.getForObject("http://zuul/ssydx/provider/dc/", String.class);
    }

}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务, 此处等价于 @EnableEurekaClient, 它同时也适用于其他注册中心
@EnableDiscoveryClient
public class EurekaConsumerProviderApplication_9006 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumerProviderApplication_9006.class, args);
    }
}

consumer

载入依赖

同 provider

编写配置

spring:
  application:
    name: eureka-consumer
server:
  port: 9005

eureka:
  instance:
    instance-id: eureka-consumer-single
  client:
    # 实际生产中, 通常所有微服务都会注册到服务中心, 保证受到网关的管理
    register-with-eureka: true
    service-url:
      # 注册中心位置
      defaultZone: http://eureka7001.com:7001/eureka/, http://eureka7002.com:7002/eureka/, http://eureka7003.com:7003/eureka/

配置类

同 consumer-provider

控制器

package xyz.ssydx.springcloud.controller;

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

@RestController
public class MyController {
    @Autowired
    private RestTemplate restTemplate;

    @RequestMapping("/dc")
    public String dc() {
        // 未经过zuul
        return restTemplate.getForObject("http://eureka-consumer-provider/dc/", String.class);
    }

}

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
// 作为 Eureka 的客户端, 即服务, 此处等价于 @EnableEurekaClient, 它同时也适用于其他注册中心
@EnableDiscoveryClient
public class EurekaConsumerApplication_9005 {
    public static void main(String[] args) {
        SpringApplication.run(EurekaConsumerApplication_9005.class, args);
    }
}

zuul

载入依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
    </dependency>
</dependencies>

编写配置

server:
  port: 11000

spring:
  application:
    name: zuul

eureka:
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
  instance:
    instance-id: zuul-11000

zuul:
  # 路由组, 每个服务都可以进行一组映射
  routes:
    # 把 eureka-provider 服务映射到 /provider/**
    # 即: 可以通过 localhost:11000/provider/** 访问 eureka-provider 服务
    provider:
      service-id: eureka-provider
      path: /provider/**
  # 拒绝通过服务名称访问, '*' 表示所有服务名称(''不可省略)
  # 默认只要将 zuul 注册到 eureka 就可在 localhost:11000/eureka-provider/** 访问
  # 注: 不能避免直接通过服务所在 ip 进行访问, 想要实现拒绝外部直接通过 ip 访问原始服务, 需要进行网络防火墙设置
  # 注: 也不影响服务间通过服务名称调用
  ignored-services: eureka-provider
  # 给所有服务添加公共前缀
  # 现在要通过 localhost:11000/ssydx/provider/** 进行访问
  prefix: /ssydx

过滤器

package xyz.ssydx.springcloud.filter;

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

import javax.servlet.http.HttpServletRequest;

@Component
public class MyZuulFilter extends ZuulFilter {
    // 过滤器类型, pre post error route
    @Override
    public String filterType() {
        return "pre";
    }
    // 过滤器优先级
    @Override
    public int filterOrder() {
        return 0;
    }
    // 是否启用过滤器
    @Override
    public boolean shouldFilter() {
        return true;
    }
    // 过滤器的实际逻辑
    @Override
    public Object run() throws ZuulException {
        // RequestContext 是一个本地线程
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        System.out.println("============>" + request.getRequestURI());
        return null;
    }
}

主启动类

package xyz.ssydx.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
// 启用 zuul
@EnableZuulProxy
public class ZuulApplication {
    public static void main(String[] args) {
        SpringApplication.run(ZuulApplication.class, args);
    }
}

测试

浏览器访问:
http://localhost:11000/ssydx/eureka-consumer/dc

zuul 应用的控制台会输出:
============>/ssydx/eureka-consumer/dc
============>/ssydx/provider/dc/

Config

配置中心,提供一个集中的远端的配置中心,避免分散配置应用

简单示例

仓库配置

git 及 github、gitee的具体使用此处不进行讲解

演示使用 gitee,网络更稳定,且 gitee 自带教程,上手简单

生成SSH密钥对->添加公钥到gitee->创建远程仓库->克隆仓库到本地

本地仓库中编写配置文件,文件名为config-client.yml,推送至远程仓库

spring:
  application:
    name: config-client
server:
  port: 12002
eureka:
  instance:
    instance-id: config-client-default
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka

---
spring:
  profiles: dev
  application:
    name: config-client
server:
  port: 12003
eureka:
  instance:
    instance-id: config-client-dev
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka

---
spring:
  profiles: test
  application:
    name: config-client
server:
  port: 12004
eureka:
  instance:
    instance-id: config-client-test
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka

实际你也可以仅在云端创建仓库,直接在云端编写配置文件

server

使用 ribbon 的示例

server

载入依赖

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

编写配置

server:
  port: 12001

spring:
  application:
    name: config-server

  cloud:
    config:
      server:
        git:
          # 指定远程仓库的访问地址
          uri: https://gitee.com/ssydx/springcloud-config.git

# 注册到 eureka 服务器
eureka:
  instance:
    instance-id: config-server-single
  client:
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka

主启动类

package xyz.ssydx.springcloud;

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

@SpringBootApplication
@EnableDiscoveryClient
// 作为配置文件服务器
@EnableConfigServer
public class ConfigApplication_12001 {
    public static void main(String[] args) {
        SpringApplication.run(ConfigApplication_12001.class, args);
    }
}

client

载入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <!-- 等价于 -->
<!--        <dependency>-->
<!--            <groupId>org.springframework.cloud</groupId>-->
<!--            <artifactId>spring-cloud-config-client</artifactId>-->
<!--        </dependency>-->
    </dependencies>

编写配置

此处使用的boostrap.yml 而不是 application.yml

两者不可混用

前者在应用上下文初始化之前就已经加载,常用于 SpringCloud 的远程配置

后者在应用上下文初始化之后才进行加载,用于常规配置

spring:
  cloud:
    config:
      name: config-client
      # 远端 config-client.yml 中存在 三个配置片段
      # 第一个未指定 profile 名称, 会被视为 default; 另外两个分别是 dev, test
      # 如果此处未指定 profile 名称, 自动使用 default 片段
      # 如果指定, 则使用指定名称的片段
#      profile: test
      label: master
      # 硬编码地址, 不推荐
#      uri: http://localhost:12001
      # 通过服务名称访问, 前提是开启配置服务器注册到 eureka
      # 存在多个配置服务器时, 自动实现负载均衡
      discovery:
        enabled: true
        service-id: config-server

eureka:
  # 远端配置如果也配置了以下内容, 会进行同属性覆盖
  # 即远端配置加载顺序晚于本地配置
  instance:
    instance-id: config-client-single
  # 必须配置, 否则通过服务名称发现
  client:
    # 必须可抓取服务列表, 否则无法通过服务名称查询实际地址并进行负载均衡
    fetch-registry: true
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka,http://eureka7003.com:7003/eureka

控制器

package xyz.ssydx.springcloud.controller;

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

@RestController
public class MyController {
    @Value("${spring.application.name}")
    private String appName;
    @Value("${eureka.client.service-url.defaultZone}")
    private String eurekaServer;
    @Value("${server.port}")
    private String port;

    @RequestMapping("/dc")
    public String dc() {
        return "appName=" + appName + ", eurekaServer=" + eurekaServer + ", port=" + port;
    }
}

主启动类

package xyz.ssydx.springcloud;

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

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

SpringCloud Alibaba

TODO

#java##spring##springboot##springcloud#
计算机编程合集 文章被收录于专栏

本专栏包含Java、MySQL、JavaWeb、Spring、Redis、Docker等等,作为个人学习记录及知识总结,将长期进行更新! 有相关问题或错误指正欢迎交流沟通,邮箱ssydx@qq.com

全部评论

相关推荐

评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务