搭建 Spring Cloud Alibaba 微服务框架_扶摇而上者九万里的博客-程序员宅基地

技术标签: SpringCloudAlibaba  分布式  

了解微服务搭建

版本说明

版本兼容参考: alibaba/spring-cloud-alibaba

Spring Cloud: https://spring.io/projects/spring-cloud#overview

组件版本关系


Spring Cloud Alibaba Version Sentinel Version Nacos Version RocketMQ Version Dubbo Version Seata Version
2.2.5.RELEASE 1.8.0 1.4.1 4.4.0 2.7.8 1.3.0
2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE 1.8.0 1.3.3 4.4.0 2.7.8 1.3.0
2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE 1.7.1 1.2.1 4.4.0 2.7.6 1.2.0
2.2.0.RELEASE 1.7.1 1.1.4 4.4.0 2.7.4.1 1.0.0
2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE 1.7.0 1.1.4 4.4.0 2.7.3 0.9.0
2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE 1.6.3 1.1.1 4.4.0 2.7.3 0.7.1

毕业版本依赖关系(推荐使用)


Spring Cloud Version Spring Cloud Alibaba Version Spring Boot Version
Spring Cloud Hoxton.SR8 2.2.5.RELEASE 2.3.2.RELEASE
Spring Cloud Greenwich.SR6 2.1.3.RELEASE 2.1.13.RELEASE
Spring Cloud Hoxton.SR3 2.2.1.RELEASE 2.2.5.RELEASE
Spring Cloud Hoxton.RELEASE 2.2.0.RELEASE 2.2.X.RELEASE
Spring Cloud Greenwich 2.1.2.RELEASE 2.1.X.RELEASE
Spring Cloud Finchley 2.0.3.RELEASE 2.0.X.RELEASE
Spring Cloud Edgware 1.5.1.RELEASE(停止维护,建议升级) 1.5.X.RELEASE

服务注册与发现-Nacos

服务治理概念

在RPC远程调用过程中,服务与服务之间依赖关系非常大,服务Url地址管理非常复杂,所以这时候需要对我们服务的url实现治理,通过服务治理可以实现服务注册与发现、负载均衡、容错等。

服务注册中心的概念

  • 每次调用该服务如果地址直接写死的话,一旦接口发生变化的情况下,这时候需要重新发布版本才可以该接口调用地址,所以需要一个注册中心统一管理我们的服务注册与发现。
  • 注册中心:我们的服务注册到我们注册中心,key为服务名称、value为该服务调用地址,该类型为集合类型。Eureka、consul、zookeeper、nacos等。
  • 服务注册:我们生产者项目启动的时候,会将当前服务自己的信息地址注册到注册中心。
  • 服务发现: 消费者从我们的注册中心上获取生产者调用的地址(集合),在使用负载均衡的策略获取集群中某个地址实现本地rpc远程调用。

微服务调用接口常用名词

  • 生产者:提供接口被其他服务调用
  • 消费者:调用生产者接口实现消费
  • 服务注册:将当前服务地址注册到

服务发现

Nacos的基本的介绍

Nacos可以实现分布式服务注册与发现/分布式配置中心框架。

官网的介绍: https://nacos.io/zh-cn/docs/what-is-nacos.html

windows安装nacos

首先去NACOS官网 下载相关jar,这里使用的是最新版本1.4.1

  • 下载最新版本后进行解压,目前最新版本1.4.1
  • 进入解压后的目录:E:\SpringCloudAlibaba\nacos\bin
  • cmd 打开命令窗口
  • 运行: startup.cmd -m standalone

Nacos端口为8848

http://127.0.0.1:8848/nacos/#/login 账号密码nacos naocs

nacos可以支持分布式配置中心和服务注册与发现

搭建Spring Cloud Alibaba项目

首先要有一个SpringBoot项目,微服务项目是基于SpringBoot项目的,主要是由于SpringBoot项目可以不用写太多繁琐的配置文件,写过SSM的都体验过,那滋味。。。。

注意事项:必须先启动nacos,才能启动cloud的项目

搭建父工程

修改 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 https://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.3.2.RELEASE</version> <!-- Spring Boot 版本 -->
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <!-- 子模块 -->
    <modules>
        <module></module>
    </modules>

    <groupId>com.cp</groupId>
    <artifactId>springcloud-father</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-father</name>
    <description>Demo project for Spring Boot</description>

    <!-- 统一版本号 -->
    <properties>
        <java.version>1.8</java.version>
        <spring.cloud-version>Hoxton.SR8</spring.cloud-version>
        <spring.cloud.alibaba-version>2.2.5.RELEASE</spring.cloud.alibaba-version>
    </properties>

    <!--统一依赖-->
    <dependencyManagement>
        <dependencies>

            <!-- Spring Cloud -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud-version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- Spring Cloud Alibaba -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba-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>

创建生产者项目

这里我们现在Maven创建子模块,也可以使用SpringBoot创建子模块

使用SpringBoot 可以不用手动创建主启动类等一些文件

使用Maven 创建的子项目pom文件内容简短,方便建立父子模块关系

添加Nacos依赖

<!-- Nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
修改主启动类

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


@SpringBootApplication
@EnableDiscoveryClient	//添加注解,实现服务注册
public class SpringCloudProviderApplication {
    

    public static void main(String [] args){
    
        SpringApplication.run(SpringCloudProviderApplication.class,args);
    }
}
修改 application.yml 配置

server:
  port: 9000
spring:
  application:
    name: springcloud-provider  #服务名称,微服务项目中必须设计服务名称
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址

创建一个controller进行测试
package com.cp.controller;

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

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-06 10:08
 **/
@RestController
public class ProviderController {
    

    @GetMapping("/index")
    public String index(){
    
        return "Hello word";
    }
}

添加依赖

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

注意事项:必须先启动nacos,才能启动cloud的项目

访问地址:http://localhost:8848/nacos

启动完成后去nacos服务注册中心看看,发现provider生产者已经注册到了nacos,说明生产者已经搭建完成。

访问地址:http://localhost:9000/index ,如图所示,生产者已经搭建完成

创建消费者项目

创建消费者,步骤和创建生产者一样,修改一下端口号和服务名称

server:
  port: 9001
spring:
  application:
    name: springcloud-consumer  #服务名称,微服务项目中必须设计服务名称
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址

注意事项:必须先启动nacos,才能启动cloud的项目

访问地址:http://localhost:8848/nacos

启动完成后nacos注册服务中心可以看到消费者服务已经注册

服务发现

/**
 * 服务发现
 */
@Autowired
private DiscoveryClient discoveryClient;

@GetMapping("/instances")
public List<ServiceInstance> instances(){
    
    List<ServiceInstance> instances = discoveryClient.getInstances("springcloud-consumer");
    return instances;
}

注意事项:必须先启动nacos,才能启动cloud的项目

访问地址:http://localhost:9001/instances,如图所示:

消费者已经搭建完成并得到了注册信息

负载均衡-Ribbon

概述

LB(Load Balance,负载均衡)是一种集群技术,它将特定的业务(网络服务、网络流量等)分担给多台网络设备(包括服务器、防火墙等)或多条链路,从而提高了业务处理能力,保证了业务的高可靠性。

负载均衡简介

负载均衡是一种基础的网络服务,核心原理是按照指定的负载均衡算法,将请求分配到后端服务集群上,从而为系统提供并行处理和高可用的能力。

负载均衡一般分为以下两种:

  • 集中式负载均衡,在消费者和服务提供方中间使用独立的代理方式进行负载,有硬件的负载均衡器,比如 F5,也有软件,比如 Nginx。
    • F5,四层负载均衡通过虚拟 IP + 端口接收请求,然后再分配到真实的服务器
    • Nginx,七层负载均衡通过虚拟的 URL 或主机名接收请求,然后再分配到真实的服务器。
  • 客户端负载均衡,客户端根据自己的请求情况做负载,Ribbon 就属于客户端自己做负载均衡的框架。

集中式负载均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F8AoPG0X-1616120955070)(https://images1.freesion.com/158/2a/2a380343a1444f63155c1499761c494e.png)]

客户端发送请求到负债均衡器,负载均衡器根据相关的负载均衡算法(随机、轮询、加权)选择其中一台服务器,将请求转发到服务器上。

客户端负载均衡

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b8Z9QJXe-1616120955070)(https://images2.freesion.com/499/b0/b06eaa2e8cf41870af8b798bcf6f48f3.png)]

如上图所示,和集中式负载均衡的不同是,客户端负载均衡器需要自己维护服务实例的信息,然后通过相关的负载均衡算法(随机、轮询、加权)从实例中选取一个实例,直接进行访问。

负载均衡策略

轮询策略

Ribbon 默认采用轮询策略

这里我们实现消费者(consumer)调用提供者(provider)

  1. 在提供者(provider)定义方法

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @author : CP
     * @version: 1.0
     * @program : springcloud-father
     * @description :
     * @date : 2021-03-06 10:08
     **/
    @RestController
    public class ProviderController {
          
    
        //获取端口号
        @Value("${server.port}")
        private String port;
    
    
        @GetMapping("/echo")
        public String echo(){
          
            //打印当前端口号
            return "Hello word ------->"+port;
        }
    }
    
  2. 修改消费者(consumer)主启动类

    添加@LoadBalanced注解

    /**
     * @LoadBalanced 
     * 实现赋值均衡
     * 使用的是轮询策略
     */
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
          
        return new RestTemplate();
    }
    
  3. 在消费者(consumer)定义service层

    /**
     * 调用provider模块中的方法
     * @return String
     */
    String echo();
    

    
    @Autowired
    private RestTemplate restTemplate;
    
    @Override
    public String echo() {
          
        /**
         * 第一个参数获取路径
         * 第二个参数是那边接口返回的类型
         * springcloud-provider 是提供者模块yml配置的名称
         * index 是提供者里有的提供方法
         */
        String s = restTemplate.getForObject("http://springcloud-provider/index", String.class);
        return s;
    }
    
  4. 在消费者(consumer)定义Controller层

    @Autowired
    private CousmerService cousmerService;
    
    /**
     * 调用生产者提供的方法
     * @return
     */
    @GetMapping("/echo")
    public String echo(){
          
        return cousmerService.echo();
    }
    

    注意事项:必须先启动nacos,才能启动cloud的项目

    访问地址:http://localhost:9001/echo,如图所示

随机

修改消费者(consumer)模块中的配置

#springcloud-provider 是你提供者(provider)模块名称
springcloud-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

权重

在消费者(consumer)添加NacosWeightLoadBalancerRule类

package com.cp.config;


import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.netflix.client.config.IClientConfig;
import com.netflix.loadbalancer.AbstractLoadBalancerRule;
import com.netflix.loadbalancer.DynamicServerListLoadBalancer;
import com.netflix.loadbalancer.Server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * 基于Nacos权重的负载均衡
 *
 * @Author Administrator
 */
@Slf4j
public class NacosWeightLoadBalancerRule extends AbstractLoadBalancerRule {
    

    @Autowired
    private NacosDiscoveryProperties nacosDiscoveryProperties;

    @Override
    public void initWithNiwsConfig(IClientConfig iClientConfig) {
    
        // 读取配置文件,并初始化NacosWeightLoadBalancerRule
    }

    @Override
    public Server choose(Object o) {
    
        DynamicServerListLoadBalancer loadBalancer = (DynamicServerListLoadBalancer) getLoadBalancer();
        // 请求的微服务名称
        String applicationName = loadBalancer.getName();
        try {
    
            // nacos 通过基于权重的负载均衡算法,算出一个健康的服务实例以供调用
            Instance instance = nacosDiscoveryProperties.namingServiceInstance().selectOneHealthyInstance(applicationName);
            return new NacosServer(instance);
        } catch (NacosException e) {
    
            log.error("获取服务实例异常:{}", e.getMessage());
        }
        return null;
    }
}

添加依赖

 <!-- Lombok -->
 <dependency>
     <groupId>org.projectlombok</groupId>
     <artifactId>lombok</artifactId>
 </dependency>

配置文件

#springcloud-provider 是你提供者(provider)模块名称
springcloud-provider:
  ribbon:
    NFLoadBalancerRuleClassName: com.cp.config.NacosWeightLoadBalancerRule  #刚刚创建类的路径

服务调用-OpenFeign

OpenFeign简介

OpenFeign是一个声明式的Web服务客户端、让编写Web服务客户端变得更加容易只需要创建一个接口然后添加上注解即可,同时,它集成了Ribbon,可以轻松实现负载均衡的效果。

Feign和OpenFeign的区别:

快速开始

这里我们对消费者(consumer)调用提供者(provider)进行优化

在消费者(consumer)模块中添加依赖

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

在消费者(consumer)的主启动类添加注解

//支持 OpenFeign 组件的使用
@EnableFeignClients

修改消费者(consumer) service层

package com.cp.service;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @FeignClient(value = "springcloud-provider") 声明要访问的服务
 * value = 需要访问的服务名称
 * @GetMapping("/echo") 声明要调用的方法
 * /echo  必须是访问服务里拥有的方法接口
 **/
@FeignClient(value = "springcloud-provider")
public interface ConsumerService {
    

    @GetMapping("/echo")
    String echo();
}

定义后可以不用编写实现类可直接通过Controller层(不需要改动)进行调用

注意事项:必须先启动nacos,才能启动cloud的项目

访问地址:http://localhost:9001/echo,如图所示

服务容错-Sentinel

服务雪崩效应

在分布式系统中,由于网络原因或者自身的原因,服务一般无法保证100%可用。如果一个服务出现了问题,调用这个服务就会出现线程阻塞的情况。此时若有大量的请求涌入,就会出现多条线程阻塞等待,进而导致服务瘫痪。

由于服务与服务之间的依赖性,故障会传播,会对整个微服务系统造成灾难性的严重后果,这就是服务故障的“雪崩效应”。

服务雪崩效应的定义

服务雪崩效应是一种因 服务提供者 的不可用导致 服务调用者 的不可用,并将不可用 逐渐放大 的过程.如果所示:

上图中, A为服务提供者, B为A的服务调用者, C和D是B的服务调用者. 当A的不可用,引起B的不可用,并将不可用逐渐放大C和D时, 服务雪崩就形成了

服务雪崩效应形成的原因

我把服务雪崩的参与者简化为 服务提供者服务调用者, 并将服务雪崩产生的过程分为以下三个阶段来分析形成的原因:

  1. 服务提供者不可用
  2. 重试加大流量
  3. 服务调用者不可用

服务雪崩的每个阶段都可能由不同的原因造成, 比如造成 服务不可用 的原因有:

  • 硬件故障
  • 程序Bug
  • 缓存击穿
  • 用户大量请求

服务雪崩的应对策略

针对造成服务雪崩的不同原因, 可以使用不同的应对策略:

  • 服务降级:释放服务器资源以保证核心任务的正常运行
  • 服务限流:限制请求访问量
  • 服务隔离:避免服务之间相互影响
  • 服务容错:Sentinel、Hystrix、Resilience4j

Sentinel 服务容错

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

Sentinel 的主要特性:

Sentinel 的开源生态:

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

快速开始

在提供者(provider)添加依赖

<!-- sentinel 服务容错 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!-- 服务监控器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

在提供者(provider)添加YAML配置

spring:
  cloud:
    # 服务容错
    sentinel:
      transport:
        dashboard: localhost:8080

management:
  endpoints:
    web:
      exposure:
        include: '*'

提供者(provider) YAML 完整配置

server:
  port: 9000
spring:
  application:
    # 服务名称
    name: springcloud-provider  #服务名称,微服务项目中必须设计服务名称
  cloud:
    # 服务注册
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
    # 服务容错
    sentinel:
      transport:
        dashboard: localhost:8080

management:
  endpoints:
    web:
      exposure:
        include: '*'

注意:运行项目前先启动本地的sentinel-dashboard-1.8.0.jar

打开控制台启动命令:

java -jar sentinel-dashboard-1.8.0.jar

启动成功后访问: http://localhost:8080;如图所示

账号密码sentinel sentinel

进入控制台后需要先访问一下接口进行监控

Alibaba Sentinel 流控规则

Sentinel流控模式

流控是Sentinel核心功能之一,流控指的是流量控制。

  • 资源名: 唯一名称,默认请求路径
  • 针对来源: Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)
  • 阈值类型/单机阈值:
    • QPS(每秒请求数量):当调用该api的QPS达到阈值的时候,进行限流
    • 线程数:当调用该api的线程数达到阈值的时候,进行限流
  • 是否集群: 不需要集群
  • 流控模式:
    • 直接:api达到限流条件时,直接限流
    • 关联:当关联的资源达到限流阈值时,就限流自己
    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到峰值,就进行限流)【api级别的针对来源】
  • 流控效果:
    • 快速失败:直接失败,抛异常
    • Warm Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/coldFactor,经过预热时长,才达到设置的QPS阈值
    • 排队等待:匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效
直接限流

点击簇点链路后进行操作

表示1秒内查询2次就是OK,若超过次数2,就直接失败-快速失败,报默认错误。

连续快速访问:

关联限流

当A接口访问到达指定的值,将B接口进行限流

在提供者(provider)定义方法

 /**
  * 测试关联限流
  * @return
  */
 @GetMapping("/show")
 public String show(){
    
     return "2333333";
 }

目前提供者(provider)所拥有的方法

package com.cp.controller;

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

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-06 10:08
 **/
@RestController
public class ProviderController {
    

    /**
     * 获取端口号
     */
    @Value("${server.port}")
    private String port;


    /**
     * 被消费者进行调用并输出当前端口号
     * @return
     */
    @GetMapping("/echo")
    public String echo(){
    
        return "Hello word ------->"+port;
    }

    /**
     * 测试关联限流
     * @return
     */
    @GetMapping("/show")
    public String show(){
    
        return "2333333";
    }
}

编写测试类频繁访问提供者(provider)接口 来测试限流

package com.cp;

import org.springframework.web.client.RestTemplate;

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-08 14:46
 **/
public class ProviderTest {
    
    public static void main(String[] args) {
    
        RestTemplate restTemplate = new RestTemplate();
        for (int i = 0; i < 500; i++) {
    
            String forObject = restTemplate.getForObject("http://localhost:9010/show", String.class);
            try {
    
                //0.1秒延迟
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }
    }
}

通过关联/show接口;当接口每秒访问超过2时,/echo接口限流

添加限流规则后去确定测试类进行测试

访问结果:

链路限流

B和C都访问A接口,当B或C其中一个接口到达限流要求后将A接口限流

在提供者(provider)添加依赖

<!-- 链路限流所需以下三个依赖 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.0</version>	<!-- 通过版本统一可以忽略版本号 -->
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>1.8.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.8.0</version>
</dependency>

在提供者(provider) YMAL 中配置添加

spring:
  cloud: 
    sentinel: 
      filter: 
        enabled: false

提供者(provider) YAML 完整配置

server:
  port: 9000
spring:
  application:
    # 服务名称
    name: springcloud-provider  #服务名称,微服务项目中必须设计服务名称
  cloud:
    # 服务注册
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
    # 熔断器
    sentinel:
      transport:
        dashboard: localhost:8080
      filter:
        enabled: false


management:
  endpoints:
    web:
      exposure:
        include: '*'

在提供者(provider)添加配置类

package com.cp.config;

import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-10 09:35
 **/
@Configuration
public class FilterConfiguration {
    

    @Bean
    public FilterRegistrationBean registrationBean(){
    
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new CommonFilter());
        registrationBean.addUrlPatterns("/*");
        registrationBean.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY,"false");
        registrationBean.setName("sentinelFilter");
        return registrationBean;
    }
}

提供者(provider) 添加 ProviderServiceImpl 类

package com.cp.service.impl;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.stereotype.Service;

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-10 07:56
 **/
@Service
public class ProviderServiceImpl {
    

    //必须添加 @SentinelResource 才有流控效果
    @SentinelResource("/link")
    public String link(){
    
        return "链路访问结果";
    }
}

在提供者(provider) ProviderController 添加方法

    @Autowired
    private ProviderServiceImpl providerService;
	
	/**
     * 链路限流测试
     * @return
     */
    @GetMapping("/link1")
    public String link1(){
    
        providerService.link();
        return "link1";
    }

    @GetMapping("/link2")
    public String link2(){
    
        providerService.link();
        return "link2";
    }

打开Sentinel 控制台,查看相关链路

进行链路限流

选择好资源名后,流控模式选择链路

根据自己选择的资源名查看他的拥有哪些入口资源,添加一个入口资源,可添加多个用逗号隔开

当入口资源达到自己定义的阈值后选择的资源进行限流

修改之前编写过的测试类进行测试

package com.cp;

import org.springframework.web.client.RestTemplate;

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-08 14:46
 **/
public class ProviderTest {
    
    public static void main(String[] args) {
    
        RestTemplate restTemplate = new RestTemplate();
        for (int i = 0; i < 500; i++) {
    
            String forObject = restTemplate.getForObject("http://localhost:9000/link2", String.class);
            try {
    
                //0.5秒延迟
                Thread.sleep(100);
            } catch (InterruptedException e) {
    
                e.printStackTrace();
            }
        }
    }
}

运行测试类后访问/link1得到结果

资源成功的被限流了

消息驱动-RocketMQ

消息队列概述

消息队列中间件是分布式系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构。目前使用较多的消息队列有ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaMQ,RocketMQ

核心概念

  • Topic:消息主题,一级消息类型,生产者向其发送消息。
  • 生产者:也称为消息发布者,负责生产并发送消息至Topic。
  • 消费者:也称为消息订阅者,负责从Topic接收并消费消息。
  • 消息:生产者向Topic发送并最终传送给消费者的数据和(可选)属性的组合。
  • 消息属性:生产者可以为消息定义的属性,包含Message Key和Tag。
  • Group:一类生产者或消费者,这类生产者或消费者通常生产或消费同一类消息,且消息发布或订阅的逻辑一致。

Linux 安装和部署RocketMQ

Linux 配置环境:传送门

JDK: jdk-8u271-linux-x64.tar.gz

RocketMQ: rocketmq-all-4.7.1-bin-release

RocketMQ控制台: rocketmq-externals

Spring Boot 整合 RocketMQ

创建 dao 模块统一公共的依赖

pom.xml 依赖

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

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

<!-- Lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
</dependency>

创建 Order 类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Order {
    
    private Integer id;
    private String buyerName;
    private String buyerTel;
    private String address;
    private Date createDate;
}

提供者(provider) 继承dao模块

提供者(provider)添加依赖

<dependency>
    <groupId>com.cp</groupId>
    <artifactId>dao</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

<!-- Spring Boot Rocketmq -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

<!-- Rocketmq 可视化连接 -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.7.1</version>
</dependency>

提供者(provider)目前依赖

<dependency>
    <groupId>com.cp</groupId>
    <artifactId>dao</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

<!-- Nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- sentinel 服务容错 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

<!-- 服务监控器 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

<!-- 链路限流所需以下三个依赖 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-core</artifactId>
    <version>1.8.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-web-servlet</artifactId>
    <version>1.8.0</version>
</dependency>

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.8.0</version>
</dependency>

<!-- Spring Boot Rocketmq -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

<!-- Rocketmq 可视化连接 -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.7.1</version>
</dependency>

提供者(provider) 添加 application.yml 配置

rocketmq:
  name-server: 192.168.64.135:9876
  producer:
    group: myprovider

提供者(provider) 现在 YAML 配置

server:
  port: 9000
spring:
  application:
    # 服务名称
    name: springcloud-provider  #服务名称,微服务项目中必须设计服务名称
  cloud:
    # 服务注册
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848 #Nacos的服务注册中心地址
    # 熔断器
    sentinel:
      transport:
        dashboard: localhost:8080
      filter:
        enabled: false

management:
  endpoints:
    web:
      exposure:
        include: '*'

rocketmq:
  name-server: 192.168.64.135:9876
  producer:
    group: myprovider

在提供者(provider) 控制器中 定义方法

@Autowired
private RocketMQTemplate rocketMQTemplate;

@GetMapping("/create")
public Order create(){
    
    Order order = new Order(
            1,
            "张三",
            "123123",
            "软件园",
            new Date()
    );
    this.rocketMQTemplate.convertAndSend("orderTopic",order);
    return order;
}

目前提供者(provider) 控制器所拥有的方法

package com.cp.controller;

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

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-06 10:08
 **/
@RestController
public class ProviderController {
    

    /**
     * 获取端口号
     */
    @Value("${server.port}")
    private String port;


    /**
     * 被消费者进行调用并输出当前端口号
     * @return
     */
    @GetMapping("/echo")
    public String echo(){
    
        return "Hello word ------->"+port;
    }

    /**
     * 测试关联限流
     * @return
     */
    @GetMapping("/show")
    public String show(){
    
        return "2333333";
    }
    
    
    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    /**
     * 消息队列进行消息发送
     */
    @GetMapping("/create")
    public Order create(){
    
        Order order = new Order(
                1,
                "张三",
                "123123",
                "软件园",
                new Date()
        );
        this.rocketMQTemplate.convertAndSend("orderTopic",order);
        return order;
    }
}

启动前要保证nacos、ES、以及 [服务器/虚拟机] 端口号开放和打开

访问: http://localhost:9000/create 得到结果

消费者(consumer) 继承dao模块

消费者(consumer) 模块添加依赖和提供者(provider)添加依赖一致

<dependency>
    <groupId>com.cp</groupId>
    <artifactId>dao</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

<!-- Spring Boot Rocketmq -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

<!-- Rocketmq 可视化连接 -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.7.1</version>
</dependency>

消费者(consumer) 目前拥有的依赖

<dependency>
    <groupId>com.cp</groupId>
    <artifactId>dao</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

<!--nacos-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

<!-- Spring Boot Rocketmq -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-spring-boot-starter</artifactId>
    <version>2.1.0</version>
</dependency>

<!-- Rocketmq 可视化连接 -->
<dependency>
    <groupId>org.apache.rocketmq</groupId>
    <artifactId>rocketmq-client</artifactId>
    <version>4.7.1</version>
</dependency>

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

消费者(consumer) 添加 application.yml 配置

rocketmq:
  name-server: 192.168.64.138:9876

消费者(consumer) 现在 YAML 配置

spring:
  application:
    name: springcloud-consumer
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

server:
  port: 9001

rocketmq:
  name-server: 192.168.64.135:9876

消费者(consumer) 创建 ConsumeService 类 进行消息消费

消费者(consumer)会实时监控提供者(provider)是否产生消息来通过消费

package com.cp.service;

import com.cp.enitiy.Order;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Service;

/**
 * @author : CP
 * @version: 1.0
 * @program : spring-cloud-alibaba
 * @description :
 * @date : 2021-03-16 20:13
 **/
@Slf4j
@Service
@RocketMQMessageListener(consumerGroup = "myConsumer",topic = "orderTopic")
public class ConsumeService implements RocketMQListener<Order> {
    
    @Override
    public void onMessage(Order order) {
    
        log.info("新订单{},发短信",order);
    }
}

无论先启动提供者(provider)还是消费者(consumer)都没有关系

提供者(provider) 用于提供消息

消费者(consumer)实时监控提供者(provider)

启动前要保证nacos、ES、以及 [服务器/虚拟机] 端口号开放和打开

每次刷新提供者提供消息的接口,消费者都会立刻进行消费

打开 RocketMQ控制台也可以查看消费记录

java -jar rocketmq-console-ng-1.0.0.jar 启动jar包 访问自己定义的端口号

API网关-Gateway

微服务网关概述

不同的微服务一般会有不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题:

  • 客户端会多次请求不同的微服务,增加了客户端的复杂性
  • 存在跨域请求,在一定场景下处理相对复杂
  • 认证复杂,每个服务都需要独立认证
  • 难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施
  • 某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难

以上这些问题可以借助网关解决。

Gateway特性

  • 基于Spring Framework 5, Project Relactor 和 Spring Boot 2.0 进行构建;
  • 动态路由:能够匹配任何请求属性;
  • 可以对路由指定 Predicate (断言)和 Filter (过滤器) ;
  • 集成 Hystrix 的断路器功能;
  • 集成 Spring Cloud 服务发现功能;
  • 易于编写的 Predicate (断言)和Filter (过滤器) ;
  • 请求限流功能;
  • 支持路径重写;

Gateway工作流程

客户端向Spring Cloud GateWay发出请求,然后在GateWay Handler Mapping中找到与请求相匹配的路由,将其发送到GateWay Web Handler;Handler再通过指定的过滤器链来将请求发送到我们实际的服务执⾏业务逻辑,然后返回。过滤器之
间⽤虚线分开是因为过滤器可能会在发送代理请求之前(pre)或者之后(post)执⾏业务逻辑。

Filter在“pre”类型过滤器中可以做参数校验、权限校验、流量监控、⽇志输出、协议转换等,在“post”类型的过滤器中可以做响应内容、响应头的修改、⽇志的输出、流量监控等。

快速开始

创建Gateway模块

项目名为 springcloud-gateway

添加依赖

<!-- Nacos -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

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

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

特别注意

Spring Cloud Gateway 不使用 Web 作为服务器,而是 使用 WebFlux 作为服务器,Gateway 项目已经依赖了 starter-webflux,所以这里千万不要依赖starter-web

创建Gateway主启动类

package com.cp;

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

/**
 * @author : CP
 * @version: 1.0
 * @program : spring-cloud-alibaba
 * @description :
 * @date : 2021-03-19 09:35
 **/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class GatewayApplication {
    
    public static void main(String[] args) {
    
        SpringApplication.run(GatewayApplication.class,args);
    }
}

创建application.yml

在resources创建YAML文件

server:
  port: 9010
spring:
  application:
    # 服务名称
    name: springcloud-gateway  #服务名称,微服务项目中必须设计服务名称
  cloud:
    gateway:
      # 开启本地能使用服务访问路由
      discovery:
        locator:
          enabled: true
      routes:
        #springcloud-provider 提供者模块
        - id: SPRINGCLOUD-PROVIDER
          uri: lb://springcloud-provider
          predicates:
            - Method=GET,POST #请求方式
        #springcloud-consumer 消费者模块
        - id: SPRINGCLOUD-CONSUMER
          uri: lb://springcloud-consumer
          predicates:
            - Method=GET,POST
        #其他服务可继续添加

传送门: 官方文档

启动 Gateway 模块、提供者(provider)模块、消费者(consumer)模块

访问提供者(provider)模块

访问消费者(consumer)模块

鉴权过滤器

添加后访问必须携带请求头token才能进行访问

package com.cp.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.Map;

/**
 * 鉴权过滤器
 */
@Component
public class AuthFilter implements GlobalFilter, Ordered {
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    
        String token = exchange.getRequest().getQueryParams().getFirst("token");

        if (token == null || token.isEmpty()) {
    
            ServerHttpResponse response = exchange.getResponse();

            // 封装错误信息
            Map<String, Object> responseData = Maps.newHashMap();
            responseData.put("code", 401);
            responseData.put("message", "非法请求");
            responseData.put("cause", "Token is empty");

            try {
    
                // 将信息转换为 JSON
                ObjectMapper objectMapper = new ObjectMapper();
                byte[] data = objectMapper.writeValueAsBytes(responseData);

                // 输出错误信息到页面
                DataBuffer buffer = response.bufferFactory().wrap(data);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                return response.writeWith(Mono.just(buffer));
            } catch (JsonProcessingException e) {
    
                e.printStackTrace();
            }
        }

        return chain.filter(exchange);
    }

    /**
     * 设置过滤器的执行顺序
     * @return
     */
    @Override
    public int getOrder() {
    
        return Ordered.LOWEST_PRECEDENCE;
    }
}

配置管理-Nacos

什么是配置

我们应用程序在运行过程中需要读取一切配置信息,这些信息会伴随程序的整个生命周期。例如:数据库的配置

什么是配置中心

随着微服务的兴起,配置文件也随之增加并且分散冗余,配置中心就是将配置文件从应用中剥离出来进行统一的管理,不需要我们的服务自己去管理配置。

配置中心流程
  1. 用户在配置中心更新配置信息。
  2. 服务A和服务B得到配置更新的通知,从配置中心获取配置
主流配置中心对比

目前市面上用的比较多的配置中心有:Spring Cloud Config、Apollo(携程)和Nacos(阿里)等。

对比项目 Spring Could Confi Apollo Nacos
配置实时推送 支持(Spring Cloud Bus) 支持(HTTP长轮询1s内) 支持(HTTP长轮询1s内)
版本管理 支持(Git) 支持 支持
配置回滚 支持(Git) 支持 支持
灰度发布 支持 支持 不支持
权限管理 支持(依赖Git) 支持 不支持
多集群 支持 支持 支持
多环境 支持 支持 支持
监听查询 支持 支持 支持
多语言 只支持Java 主流语言,提供了Open API 主流语言,提供了Open API
配置格式校验 不支持 支持 支持
单机读(QPS) 7(限流所致) 9000 15000
单击写(QPS) 5(限流所致) 1100 1800
3节点读 (QPS) 21(限流所致) 27000 45000
3节点写 (QPS) 5(限流所致) 3300 5600
  1. 从配置中心角度来看,性能方面Nacos的读写性能最高,Apollo次之,Spring Cloud Config依赖Git场景不适合开 放的大规模自动化运维API。
  2. 功能方面Apollo最为完善,nacos具有Apollo大部分配置管理功能,而Spring Cloud Config不带运维管理界面,需要自行开发。Nacos的一大优势是整合了注册中心、配置中心功能,部署和操作相比 Apollo都要直观简单,因此它简化了架构复杂度,并减轻运维及部署工作。

快速开始

发布配置

1、需要在 Nacos Server 中创建配置文件,采用YAML的方式部署配置文件,操作流程如下:

浏览器打开 http://127.0.0.1:8848/nacos,访问 Nacos Server

2、修改提供者(provider) resources 目录下的配置文件

添加bootstrap.properties

# 这里的应用名对应 Nacos Config 中的 Data ID,实际应用名称以配置中心的配置为准
spring.application.name=springcloud-provider-config
# 指定查找名为 nacos-provider-config.yaml 的配置文件
spring.cloud.nacos.config.file-extension=yaml
# Nacos Server 的地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

为了避免出现问题将提供者(provider)application.yml删除或注释

3、修改提供者(provider) ProviderController 类

在类上添加@RefreshScope可以达到服务端修改配置后立刻得到反应

注入ConfigurableApplicationContext方式将要以applicationContext.getEnvironment().getProperty(“user.name”);来取值

package com.cp.controller;

import com.cp.service.impl.ProviderServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-06 10:08
 **/
@RefreshScope //范围刷新
@RestController
public class ProviderController {
    

    @Autowired
    private ProviderServiceImpl providerService;

    /**
     * 获取端口号
     */
    @Value("${server.port}")
    private String port;

    /**
     * 获取自定义名称
     */
    @Value("${user.name}")
    private String name;


    /**
     * 被消费者进行调用并输出当前端口号
     * @return
     */
    @GetMapping("/echo")
    public String echo(){
    
        return "Hello word ------->"+port;
    }

    /**
     * 测试关联限流
     * @return
     */
    @GetMapping("/show")
    public String show(){
    
        return "2333333";
    }


    /**
     * 链路限流测试
     * @return
     */
    @GetMapping("/link1")
    public String link1(){
    
        providerService.link();
        return "link1";
    }

    @GetMapping("/link2")
    public String link2(){
    
        providerService.link();
        return "link2";
    }


//    /**
//     * 注入配置文件上下文
//     */
//    @Autowired
//    private ConfigurableApplicationContext applicationContext;
    
    @GetMapping("/getName")
    public String getName(){
    
//        return applicationContext.getEnvironment().getProperty("user.name");
        return name;
    }

}

ableApplicationContext方式将要以applicationContext.getEnvironment().getProperty(“user.name”);来取值

package com.cp.controller;

import com.cp.service.impl.ProviderServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author : CP
 * @version: 1.0
 * @program : springcloud-father
 * @description :
 * @date : 2021-03-06 10:08
 **/
@RefreshScope //范围刷新
@RestController
public class ProviderController {
    

    @Autowired
    private ProviderServiceImpl providerService;

    /**
     * 获取端口号
     */
    @Value("${server.port}")
    private String port;

    /**
     * 获取自定义名称
     */
    @Value("${user.name}")
    private String name;


    /**
     * 被消费者进行调用并输出当前端口号
     * @return
     */
    @GetMapping("/echo")
    public String echo(){
    
        return "Hello word ------->"+port;
    }

    /**
     * 测试关联限流
     * @return
     */
    @GetMapping("/show")
    public String show(){
    
        return "2333333";
    }


    /**
     * 链路限流测试
     * @return
     */
    @GetMapping("/link1")
    public String link1(){
    
        providerService.link();
        return "link1";
    }

    @GetMapping("/link2")
    public String link2(){
    
        providerService.link();
        return "link2";
    }


//    /**
//     * 注入配置文件上下文
//     */
//    @Autowired
//    private ConfigurableApplicationContext applicationContext;
    
    @GetMapping("/getName")
    public String getName(){
    
//        return applicationContext.getEnvironment().getProperty("user.name");
        return name;
    }

}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/m0_46210779/article/details/115000669

智能推荐

Base64学习记录_base64 末尾是固定的吗-程序员宅基地

Base64只是一个固定的转码,不安全的,是完全不安全的,只是将内容不能使肉眼辨认内容而已 String str="测试数据"; //转码Base64 Stringencode=Base64.getEncoder().encodeToString(str.getBytes()); System.out.println(encode); //解码Base64 byte[] decode = Base64.ge._base64 末尾是固定的吗

程序运行流程——链接、装载及执行-程序员宅基地

在阅读完《深入理解计算机系统》第一章(计算机系统漫游)、第七章(链接)以及第十章(虚拟存储器)和《程序员的自我修养——链接、装载与库》后,历时悠久的梦想终于要实现了。开篇之初,首先提出一个迷惑了很久的一个问题:什么是虚拟存储器?它跟进程的虚拟地址空间有什么关系?虚拟存储器是建立在主存--辅存物理结构基础上,有附加的硬件装置及操作系统存储管理软件组成的一种存储体系。

浅谈运维平台选型,提速DevOps运维_统一运维平台选型对比-程序员宅基地

现如今DevOps已经深入人心,在这个大量数据中心建设加速的时代,运维部门都在高度强调自动化,而自动化的关键即DevOps。但是,大家在推进DevOps的过程中却发现其前途坎坷。  一种方案是建设自己的开发队伍从头开始,做CMDB、做监控、做自动化、做流程、做服务目录、做大屏展现,这种造轮子方法需要强大持续的研发投入,成本极高;第二种方案则是寻找开源产品改造,以适合自己,如CMDBBuil_统一运维平台选型对比

linux 计算器 c语言,大神教你如何用C语言实现科学计算器-程序员宅基地

原标题:大神教你如何用C语言实现科学计算器用C实现的科学计算器使用C语言写的科学计算器,可以实现四则运算、三角函数运算、指对数运算;优先级正确;能智能屏蔽空格,能识别输入错误和运算错误,能实现继续运算、清空运算结果和有效退出的功能 附上代码#include #include #include #define INPUT_MAX 1000#define NODE_MAX 500#define NUM...

计算机组成原理的教案,计算机组成原理全套教案-程序员宅基地

计算机组成原理全套教案 (12页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!9.9 积分计算机组成原理第1章概论一、 教学目标掌握:存储程序的概念、计算机系统的组成、计算机的工作过程、计算机的主要性能指 标。了解:电子计算机的发展简史、存储程序的概念、计算机系统的组成、计算机的工作过 程、计算机的主要性能指标。二、 课时分配本章安排6课时。其中,理论..._计算机组成教学教案

用vb编写一个简易的编译器界面_vb编译器-程序员宅基地

初学VC写了一个简单的编译器界面,请各位大佬赐教!1、工程代码块:2、系统主界面3、读取文件,编辑文件,复制,剪切,粘贴等小功能实现4、显示/隐藏工具栏目前还在完善中,有啥改进意见的我们可以一起讨论哦~~..._vb编译器

随便推点

在ABB机器人中利用multitasking模块和PC Interface模块创建多任务_abbpcinterface_ಥ_ಥLeerorz的博客-程序员宅基地

文章目录多任务的任务类型多任务的设置多任务的任务类型Normal:普通任务Semistatic:半静态任务,热启动后,任务从main程序起点开始重新执行。Static:静态任务,热启动后,任务从当前指针位置执开始行。多任务的设置虚拟示教器的控制面板页面虚拟示教器的配置——配置系统参数 ==>> 主题——controller选择Task后,点击显示全部选择添加,进入新建task页面,设置task类型(TYPE)和task的值(建议根据自己要实现的task功能定义_abbpcinterface

使用Tenable Nessus和PVS检测Intel AMT漏洞 (INTEL-SA-00075)-程序员宅基地

英特尔最近宣布针对英特尔主动管理技术(AMT),英特尔标准可管理系统(ISM)和英特尔小型企业技术固件,从版本6至11.6中的漏洞进行固件升级。该漏洞多年来一直存在于英特尔芯片组中,特别是管理引擎(ME)。 ME可以像DRM(数字版权管理)一样运行,可以让TPM(可信平台模块)和AMT一样工作。关于AMTAMT使系统管理员可以通过远程连接重新映像裸机。为了实现这一点,AMT需要开启许多权限,...

STM32的CAN波特率设置方法详解_stm32can波特率设置-程序员宅基地

一般来说,同一个波特率可以对应多组参数,但是要让通信更稳定,则需要选择采样点尽量靠近CIA推荐值的那一组CIA推荐采样点波特率采样点【sample point】<=500K87.5%>500K80%>800K75%波特率计算公式:波特率 = 频率/(CAN_BS1+CAN_BS2+1)/CAN_Prescaler采样点计算方式:smp = (1+CAN_BS1)/(1+CAN_BS1+CAN_BS2)以上内容如有错误或描述不合理的地方_stm32can波特率设置

多线程MPICH2-1.4.1安装_mpiexec2 安装_无衣°的博客-程序员宅基地

参考windows安装MPICH但安装时出错如下:运行exe文件时要加./表示当前目录,OK!某教程提及,故为方便使用,添加了个环境变量。_mpiexec2 安装

查漏补缺个人总结_查漏补缺自我总结-程序员宅基地

数据结构Java语言数据库GCsocket小细节算法题_查漏补缺自我总结

linux 下显卡优化,[转载]Linux 下 NVIDIA 显卡闭源驱动的一些优化-程序员宅基地

完全搬运,原文请猛戳NVIDIA 对开源驱动开发的支持之差从 Linus Torvalds 那句著名的“FuckNVIDIA”就可见一斑——几乎没有提供任何开发文档,开源驱动的开发基本要通过逆向工程进行。因而,想要获得较好的 3D 加速性能、VDPAU 硬件解码功能、完整的多头显示支持等等,你必须使用 NVIDIA闭源驱动。不过闭源驱动的一大问题就是文档匮乏、过时,一大堆神奇设置(不少还是隐藏的)...