Notas de estudio introductorias de SpringCloud (parte)

Aquí hay algunos enlaces primero.

Este artículo explica la arquitectura de microservicios en detalle : Los principiantes en microservicios deben leer este artículo. Comprender los microservicios será muy útil para el aprendizaje futuro.

Comprensión profunda del registro y descubrimiento de servicios : la explicación es fácil de entender y usted puede comprender el descubrimiento y el registro de servicios.

1. Crear un proyecto principal Espacio de proyecto

1.1 Crear un proyecto maven vacío

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

1.2 Filtrado de archivos (no mostrado)

Agregue los siguientes dos archivos inútiles
Insertar descripción de la imagen aquí

1.3 Eliminar src y modificar pom

1.3.1 La estructura del proyecto es la siguiente

Insertar descripción de la imagen aquí

1.3.2 pom agregar dependencias

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

    <groupId>com.atguigu.springcloud</groupId>
    <artifactId>cloud2020</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <!-- 统一管理jar包版本 -->
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <junit.version>4.12</junit.version>
        <log4j.version>1.2.17</log4j.version>
        <lombok.version>1.16.18</lombok.version>
        <mysql.version>5.1.47</mysql.version>
        <druid.version>1.1.16</druid.version>
        <mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version>
    </properties>

    <!-- 子模块继承之后,提供作用:锁定版本+子 module不用写groupId和version  -->
    <dependencyManagement>
        <dependencies>
            <!--spring boot 2.2.2-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.2.2.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud Hoxton.SR1-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--spring cloud alibaba 2.1.0.RELEASE-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.spring.boot.version}</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

1.3.2.1 Función de gestión de dependencias

Permita que todos los subproyectos hagan referencia a una dependencia sin enumerar explícitamente el número de versión. Si el subproyecto necesita importar este paquete y el número de versión debe ser el mismo que la etiqueta en dependencyManagement, no es necesario escribirlo.
Insertar descripción de la imagen aquí
La ventaja de esto es: si hay varios subproyectos que hacen referencia a la misma dependencia, puede evitar declarar un número de versión en cada subproyecto utilizado, de modo que cuando desee actualizar o cambiar a otra versión, solo necesite para declarar un número de versión en el nivel superior Las actualizaciones en el contenedor principal no requieren la modificación de los subproyectos uno por uno; además, si un subproyecto requiere otra versión, solo necesita declarar la versión.

  • DependencyManagement solo declara dependencias y no implementa la introducción, por lo que los subproyectos deben mostrar las dependencias requeridas.

  • Si la dependencia no se declara en el subproyecto, no se heredará del proyecto principal; solo si la dependencia está escrita en el subproyecto y no se especifica una versión específica, el elemento se heredará del proyecto principal. y la versión y el alcance Ambos se leen del pom principal;

  • Si se especifica un número de versión en el subproyecto, se utilizará la versión jar especificada en el subproyecto.

1.3.2.2 El papel de las dependencias de arranque de primavera

Cuando usamos Spring o Spring-Boot para desarrollar un proyecto, necesitamos introducir muchas dependencias, incluidos los componentes propios de Spring, varios arrancadores de Spring-Boot y otras dependencias de terceros (como: slf4j, redis).
Con demasiadas dependencias, la elección de la versión es un problema y me temo que la versión incorrecta provocará algunos errores inesperados.

Por lo tanto, Spring proporciona Spring-boot-dependencies para facilitar la gestión de las dependencias del proyecto. Solo necesita configurar la versión de Spring-boot-dependencies en dependencyManagement. No es necesario especificar otros números de versión en las dependencias, como en el pom anterior.

Hacemos clic en spring-boot-dependencies para verlo y podrá ver algo como lo siguiente, que también es un pom con números de versión específicos.

<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test-autoconfigure</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-actuator</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
</dependencyManagement>

1.3.2.3 función de dependencias de arranque de primavera

Spring proporciona spring-boot-dependencies para facilitar la gestión de las dependencias del proyecto, unificar números de versión y administrarlas. Proporciona muchas dependencias. Solo necesitamos completar la versión de spring-boot-dependencies.

spring-boot-dependencies también es un pom, lo siguiente es parte de su contenido

 <properties>
    <commons-lang3.version>3.9</commons-lang3.version>
    <commons-pool.version>1.6</commons-pool.version>
 </properties>
<dependencyManagement>
    <dependencies>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-test</artifactId>
        <version>2.2.2.RELEASE</version>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>${commons-lang3.version}</version>
      </dependency>
      <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>${commons-pool2.version}</version>
      </dependency>
</dependencyManagement>

Una de las formas de usarlo es que el proyecto principal usa dependencias de arranque de primavera, y el submódulo solo necesita introducir las dependencias sin completar el número de versión.

2. Crear módulo de pago nube-proveedor-pago8001

2.1 Crear un nuevo módulo, nombre del módulo nube-proveedor-pago8001

Insertar descripción de la imagen aquí

2.2 Crear pompón

<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-provider-payment8001</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mysql-connector-java-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--jdbc-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

2.3 Crear application.yml y PaymentMapper.xml

server:
  port: 8001

spring:
  application:
    name: cloud-payment-service
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource            # 当前数据源操作类型
    driver-class-name: com.mysql.jdbc.Driver              # mysql驱动包
    url: jdbc:mysql://localhost:3306/cloud2020?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 123456

mybatis:
  mapperLocations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.springcloud.entities    # 所有Entity别名类所在包

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >

<mapper namespace="com.atguigu.springcloud.dao.PaymentDao">

    <insert id="create" parameterType="Payment" useGeneratedKeys="true" keyProperty="id">
        insert into payment(serial)
        values (#{serial});
    </insert>

    <resultMap id="BaseResultMap" type="com.atguigu.springcloud.entities.Payment">
        <id column="id" property="id" jdbcType="BIGINT"/>
        <id column="serial" property="serial" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="getPaymentById" parameterType="Long" resultMap="BaseResultMap">
        select *
        from payment
        where id = #{id};
    </select>

</mapper>

2.4 Crear controlador de servicio-dao-entidad

package com.atguigu.springcloud.entities;

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

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
    
    
    private Integer code;
    private String  message;
    private T       data;

    public CommonResult(Integer code,String message)
    {
    
    
        this(code,message,null);
    }
}

package com.atguigu.springcloud.entities;

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

import java.io.Serializable;

/**
 * @auther zzyy
 * @create 2020-02-18 17:22
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable
{
    
    
    private Long id;
    private String serial;
}

package com.atguigu.springcloud.dao;

import com.atguigu.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

/**
 * @auther zzyy
 * @create 2020-02-18 10:27
 */
@Mapper
public interface PaymentDao
{
    
    
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}

package com.atguigu.springcloud.service;

import com.atguigu.springcloud.entities.Payment;
import org.apache.ibatis.annotations.Param;

/**
 * @auther zzyy
 * @create 2020-02-18 10:40
 */
public interface PaymentService
{
    
    
    public int create(Payment payment);

    public Payment getPaymentById(@Param("id") Long id);
}


`package com.atguigu.springcloud.service.impl;

import com.atguigu.springcloud.dao.PaymentDao;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-18 10:40
 */
@Service
public class PaymentServiceImpl implements PaymentService
{
    
    
    @Resource
    private PaymentDao paymentDao;

    public int create(Payment payment)
    {
    
    
        return paymentDao.create(payment);
    }

    public Payment getPaymentById(Long id)
    {
    
    
        return paymentDao.getPaymentById(id);
    }
}
``
```java
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import com.atguigu.springcloud.service.PaymentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 */
@RestController
@Slf4j
public class PaymentController{
    
    
    @Resource
    private PaymentService paymentService;

    @Value("${server.port}")
    private String serverPort;

    @PostMapping(value = "/payment/create")
    public CommonResult create(Payment payment)
    {
    
    
        int result = paymentService.create(payment);
        log.info("*****插入结果:"+result);

        if(result > 0)
        {
    
    
            return new CommonResult(200,"插入数据库成功,serverPort: "+serverPort,result);
        }else{
    
    
            return new CommonResult(444,"插入数据库失败",null);
        }
    }

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id)
    {
    
    
        Payment payment = paymentService.getPaymentById(id);

        if(payment != null)
        {
    
    
            return new CommonResult(200,"查询成功,serverPort:  "+serverPort,payment);
        }else{
    
    
            return new CommonResult(444,"没有对应记录,查询ID: "+id,null);
        }
    }
}

2.5 Crear clase de inicio

package com.atguigu.springcloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @auther zzyy
 * @create 2020-02-17 21:13
 */
@SpringBootApplication
public class PaymentMain8001
{
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(PaymentMain8001.class, args);
    }
}

2.6 Interfaz de creación de pruebas

Insertar descripción de la imagen aquí

3 Cree el módulo de pedidos del consumidor cloud-consumer-order80

El orden es el anterior, no se escribirán subtítulos.

<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-order80</artifactId>

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

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>
server:
  port: 80

spring:
  application:
    name: cloud-order-service
package com.atguigu.springcloud.entities;

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

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
    
    
    private Integer code;
    private String  message;
    private T       data;

    public CommonResult(Integer code,String message)
    {
    
    
        this(code,message,null);
    }
}

package com.atguigu.springcloud.entities;

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

import java.io.Serializable;

/**
 * @auther zzyy
 * @create 2020-02-18 17:22
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable
{
    
    
    private Long id;
    private String serial;
}

package com.atguigu.springcloud.config;

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

/**
 * @auther zzyy
 * @create 2020-02-18 17:27
 */
@Configuration
public class ApplicationContextConfig {
    
    
    @Bean
    public RestTemplate getRestTemplate() {
    
    
        return new RestTemplate();
    }
}
package com.atguigu.springcloud.controller;

import com.atguigu.springcloud.entities.CommonResult;
import com.atguigu.springcloud.entities.Payment;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@RestController
@Slf4j
public class OrderController {
    
    
    public static final String PAYMENT_URL = "http://localhost:8001";

    @Resource
    private RestTemplate restTemplate;

    @GetMapping("/consumer/payment/create")
    public CommonResult<Payment> create(Payment payment) {
    
    
        return restTemplate.postForObject(PAYMENT_URL + "/payment/create", payment, CommonResult.class);
    }

    @GetMapping("/consumer/payment/get/{id}")
    public CommonResult<Payment> getPayment(@PathVariable("id") Long id) {
    
    
        return restTemplate.getForObject(PAYMENT_URL + "/payment/get/" + id, CommonResult.class);
    }

}

Insertar descripción de la imagen aquí

4. Extrae la parte pública

4.1 Crear el módulo común cloud-api-commons

Mover aquí las clases de entidad de los módulos de pago y consumo

package com.atguigu.springcloud.entities;

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

/**
 * @auther zzyy
 * @create 2020-02-18 17:23
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class CommonResult<T>
{
    
    
    private Integer code;
    private String  message;
    private T       data;

    public CommonResult(Integer code,String message)
    {
    
    
        this(code,message,null);
    }
}

package com.atguigu.springcloud.entities;

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

import java.io.Serializable;

/**
 * @auther zzyy
 * @create 2020-02-18 17:22
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Payment implements Serializable
{
    
    
    private Long id;
    private String serial;
}

<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-api-commons</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.6.4</version>
        </dependency>
    </dependencies>
</project>

4.2 Eliminar las clases de entidad de los módulos de pago y consumo y agregar dependencias de módulos comunes

Simplemente agregue esos dos módulos por separado.

 <!--公有的通用包-->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>

5. Cree el servidor EurekaServer cloud-eureka-server7001

5.1 Cree pom, yml y clases de inicio. Recuerde anotar la clase de inicio con @EnableEurekaServer y usar el proyecto como centro de registro en Spring Cloud.

<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server7001</artifactId>

    <dependencies>
        <!--eureka-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--boot web actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>
server:
  port: 7001

eureka:
  instance:
    hostname: locathost #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己。
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #设置与Eureka server交互的地址查询服务和注册服务都需要依赖这个地址。
      defaultZone: http://${
    
    eureka.instance.hostname}:${
    
    server.port}/eureka/

package com.atguigu.springcloud;

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

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

5.2 Pruebas

Ejecute la prueba e ingrese http://localhost:7001/. Si ve la página correspondiente, significa que fue exitoso.

6. Los servicios de pago y pedidos de consumidores están registrados en EurekaServer.

6.1 Registro de pago

6.1.1 Agregar dependencias y registro de configuración

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
eureka:
  client:
    #表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka

6.1.2 Agregar la anotación @EnableEurekaClient a la clase de inicio

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

Luego inicie el centro de registro 7001, inicie el servicio de pago 8001, ingrese http://127.0.0.1:7001/ y podrá ver la instancia del servicio.Insertar descripción de la imagen aquí

6.2 Registro de pedidos

Similar al anterior

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
eureka:
  client:
    #表示是否将自己注册进Eurekaserver默认为true。
    register-with-eureka: true
    #是否从EurekaServer抓取已有的注册信息,默认为true。单节点无所谓,集群必须设置为true才能配合ribbon使用负载均衡
    fetchRegistry: true
    service-url:
      defaultZone: http://localhost:7001/eureka
@SpringBootApplication
@EnableEurekaClient
public class CloudConsumerorder80 {
    
    
    public static void main(String[] args) {
    
    
        SpringApplication.run(CloudConsumerorder80.class, args);
    }
}

7.Construcción del entorno del clúster Eureka

7.1 modificación del host

Modificar host

127.0.0.1 eureka7001.com
127.0.0.1 eureka7002.com

7.2 modificación yml de cloud-eureka-server7001

server:
  port: 7001

eureka:
  instance:
    hostname: eureka7001.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己。
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #集群指向其它eureka
      defaultZone: http://eureka7002.com:7002/eureka/
      #单机就是7001自己
      #defaultZone: http://eureka7001.com:7001/eureka/

Debido a que se agrega el mapeo, acceder a eureka7001.com en realidad accederá a 127.0.0.1

7.3 Crear módulo cloud-eureka-server7002

<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-eureka-server7002</artifactId>

    <dependencies>
        <!--eureka-server-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--boot web actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>
server:
  port: 7002

eureka:
  instance:
    hostname: eureka7002.com #eureka服务端的实例名称
  client:
    #false表示不向注册中心注册自己。
    register-with-eureka: false
    #false表示自己端就是注册中心,我的职责就是维护服务实例,并不需要去检索服务
    fetch-registry: false
    service-url:
      #集群指向其它eureka
      defaultZone: http://eureka7001.com:7001/eureka/
      #单机就是7001自己
      #defaultZone: http://eureka7001.com:7001/eureka/
package com.atguigu.springcloud;

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

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

7.4 Iniciar pruebas

Inicie 7001 y 7002 respectivamente
y visite http://127.0.0.1:7001/ y http://127.0.0.1:7002.
Puede ver que hay otras partes en DS Replicas.

8. Los servicios de pedidos y pagos están registrados en el clúster Eureka.


Modifique el yml original de los módulos cloud-consumer-order80 y cloud-provider-paid8001 defaultZoney reemplácelo por el siguiente

defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

Inicie la prueba y podrá ver dos centros de registro, ambos con servicios de pedidos y pagos.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

9. Configuración del clúster de microservicios de pago

9.1 cambios en el orden del consumidor en la nube 80

9.1.1 Cambiar dirección de acceso

OrderControllerModifique la dirección PAYMENT_URLy llámela a través del nombre del microservicio registrado en eureka. Debido a que el servicio de pago es un clúster, el http://localhost:8001 original solo puede acceder a 8001 en lugar de cualquiera en el clúster.

public static final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";

9.1.2 Utilice la anotación @LoadBalanced para darle a RestTemplate la capacidad de equilibrar la carga

Agregue anotaciones al configurar RestTemplate, de modo que el acceso de rotación predeterminado a los dos servicios de pago se pueda ver a través de los resultados de salida de la capa de control del servicio de pago.
Agregue el siguiente servicio de pago al clúster
y luego acceda directamente a http://localhost/consumer/paid/get/1 sin agregar esta anotación. Se informará un error porque los dos servicios de pago exponen CLOUD-PAYMENT-SERVICE y el servicio de pedidos. No sabe a qué servicio de pago específico se debe acceder, por lo que después de agregar la anotación de equilibrio de carga, se puede seleccionar uno para acceder según el algoritmo.

@Configuration
public class ApplicationContextConfig {
    
    
    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
    
    
        return new RestTemplate();
    }
}

9.2 modificación del pago 8001 del proveedor de la nube

También es necesario cambiar la dirección de registro y cambiarla al modo clúster.

defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka

9.3 Crear módulo de pago de proveedor de nube 8002 para agrupación

Al igual que cloud-provider-paid8001, después de crear un nuevo módulo, copie otras cosas, cambie la clase de inicio y cambie el puerto a 8002.

9.4 Pruebas

  1. Primer inicio de EurekaServer, servicio 7001/7002
  2. Luego inicie el proveedor de servicios, servicio 8001/8002
  3. http://localhost/consumidor/pago/get/1
  4. Resultado: se logra el efecto de equilibrio de carga y los puertos 8001/8002 aparecen alternativamente.

Regístrese y mírese unos a otros.
Insertar descripción de la imagen aquí

10.Abrir Fingir

¿Qué puede hacer Fingir?

Feign tiene como objetivo facilitar la escritura de clientes Java Http.
Cuando se usaba anteriormente Ribbon+RestTemplate, RestTemplate se usaba para encapsular solicitudes http y formar un conjunto de métodos de llamada con plantilla. Sin embargo, en el desarrollo real, dado que las dependencias de servicios se pueden llamar en más de un lugar y, a menudo, se llama a una interfaz en varios lugares, algunas clases de cliente generalmente se encapsulan para cada microservicio para empaquetar las llamadas de estos servicios dependientes. Por lo tanto, Feign lo ha encapsulado aún más sobre esta base y nos ayudará a definir e implementar la definición de interfaces de servicio dependientes. Bajo la implementación de Feign, solo necesitamos crear una interfaz y configurarla usando anotaciones (en el pasado, la interfaz Dao estaba marcada con anotaciones de Mapper, y ahora es una interfaz de microservicio con una anotación Feign) para completar el servicio. El enlace de interfaz simplifica
el desarrollo de clientes de llamadas de servicio encapsulados automáticamente cuando se utiliza Spring Cloud Ribbon.

Feign integra Ribbon

Ribbon se utiliza para mantener la información de la lista de servicios de Pago y el equilibrio de carga del cliente se implementa mediante sondeo. A diferencia de Ribbon, con fingir solo necesita definir la interfaz de enlace del servicio y usar un método declarativo para implementar llamadas de servicio de manera elegante y simple.

10.1 Descripción general del proceso:

OpenFeign reemplaza el código RestTemplate anterior. También está escrito en Application Client. Coloque la interfaz OpenFeign por separado en el paquete fingir para representar la capa de llamada de servicio. Cuando necesite llamar a otros servicios, inyecte directamente el objeto de interfaz OpenFeign para llamar al servicio remoto como si llamara al método local.

  1. ApplicationService registra el servicio con Eureka Server.
  2. El cliente de aplicación descubre información de servicio del servidor Eureka.
  3. Llame al método en la interfaz OpenFeign en Application Client
  4. En Application Client, OpenFeign llama al servicio de aplicaciones a través del nombre de la aplicación.

Insertar descripción de la imagen aquí

10.2 Diferencias relativas de simulación

OpenFeign es el soporte de Spring Cloud para anotaciones SpringMVC basadas en Feign, como @RequesMapping, etc. @FeignClient de OpenFeign puede analizar la interfaz bajo la anotación @RequestMapping de SpringMVC, generar clases de implementación a través de un proxy dinámico, realizar equilibrio de carga y llamar a otros servicios en las clases de implementación.

10.3 Crear orden fingido del consumidor en la nube80

10.3.1 Crear pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-consumer-feign-order80</artifactId>

    <dependencies>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--eureka client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>
</project>

10.3.2 Crear aplicación.yml

server:
  port: 80

eureka:
  client:
    register-with-eureka: false
    service-url:
      defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/

logging:
  level:
    # feign日志以什么级别监控哪个接口
    com.atguigu.springcloud.service.PaymentFeignService: debug

10.3.3 Cree una clase de inicio y agregue la anotación @EnableFeignClients para habilitar openfeign

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

10.3.4 Crear capa de servicio

Lo que se crea es una interfaz y el método es exactamente el mismo que la capa de control del servicio de pago.
Copie todo, desde la anotación hasta el final de los parámetros del método.
Los parámetros predeterminados de @FeignClient representan: especifique el nombre de FeignClient. Si el proyecto usa Ribbon, el atributo de nombre se usará como el nombre del microservicio para el descubrimiento de servicios.

@FeignClient("CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
    
    

    @GetMapping(value = "/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id);
}

10.3.5 Crear capa de control

Simplemente llame directamente al método de la capa de servicio, como llamar a un servicio normal, para acceder al servicio de pago.

@RestController
public class OrderFeignController {
    
    
    @Resource
    private PaymentFeignService paymentFeignService;

    @GetMapping(value = "/consumer/payment/get/{id}")
    public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
    
    
        return paymentFeignService.getPaymentById(id);
    }

}

10.3.6 Pruebas

  1. Primero inicie 2 clústeres eureka 7001/7002
  2. Iniciar 2 microservicios más 8001/8002
  3. Iniciar el inicio de OpenFeign
  4. http://localhost/consumidor/pago/get/31
  5. Feign viene con elementos de configuración de equilibrio de carga

10.4 Control de tiempo de espera de OpenFeign

在cloud-provider-payment8001más PaymentControllerinterfaz de retardo

   @GetMapping(value = "/payment/feign/timeout")
    public String paymentFeignTimeOut()
    {
    
    
        System.out.println("*****paymentFeignTimeOut from port: "+serverPort);
        //暂停几秒钟线程
        try {
    
     TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {
    
     e.printStackTrace(); }
        return serverPort;
    }

cloud-consumer-feign-order80Agregar PaymentFeignServicemétodos correspondientes a la interfaz de solicitud.

 @GetMapping(value = "/payment/feign/timeout")
    String paymentFeignTimeOut();

cloud-consumer-feign-order80Agregar OrderFeignControllermétodo de tiempo de espera

  @GetMapping(value = "/consumer/payment/feign/timeout")
    public String paymentFeignTimeOut()
    {
    
    
        return paymentFeignService.paymentFeignTimeOut();
    }

Visite el pagador http://localhost:8001/paid/feign/timeout y descubra que es normal.
Sin embargo, al acceder al consumidor http://localhost/consumer/paid/feign/timeout, se informa un error porque OpenFeign espera 1 segundo de forma predeterminada y reporta un error después de excederlo. La solución es habilitar el control de tiempo de espera del cliente OpenFeign Insertar descripción de la imagen aquí
en el archivo YML.

#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间
  ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用的时间
  ConnectTimeout: 5000

Encontrado normal durante el acceso.

11. Puerta de enlace de nueva generación

11.1 ¿Qué es?

Un componente muy importante en Cloud Family Bucket es la puerta de enlace. En la versión 1.x, se usó la puerta de enlace Zuul,
pero en la versión 2.x, la actualización de zuul siguió retrasándose. SpringCloud finalmente desarrolló una puerta de enlace para reemplazar a Zuul. ,
esa es una oración de SpringCloud Gateway:gateway是原zuul1.x版的替代

Insertar descripción de la imagen aquí
Gateway es un servicio de puerta de enlace API construido sobre el ecosistema Spring, basado en tecnologías como Spring 5, Spring Boot 2 y Project Reactor.

Gateway tiene como objetivo proporcionar una forma simple y efectiva de enrutar API, así como también proporcionar algunas funciones de filtro potentes, como disyuntor, limitación de corriente, reintento, etc.

SpringCloud Gateway es un nuevo proyecto de Spring Cloud. Es una puerta de enlace desarrollada en base a Spring 5.0 + Spring Boot 2.0 y Project Reactor, cuyo objetivo es proporcionar un método de gestión de enrutamiento API unificado simple y eficaz para la arquitectura de microservicios.

Como puerta de enlace en el ecosistema Spring Cloud, SpringCloud Gateway tiene como objetivo reemplazar a Zuul. En Spring Cloud 2.0 y superiores, la última versión de alto rendimiento de Zul 2.0 y superiores no está integrada. Zuul 1.x todavía se usa en modo no Reactor. versión antigua. Para mejorar el rendimiento de la puerta de enlace, SpringCloud Gateway se implementa en función del marco WebFlux, y la capa inferior del marco WebFlux utiliza el marco de comunicación en modo Reactor de alto rendimiento Netty.

El objetivo de Spring Cloud Gateway es proporcionar un método de enrutamiento unificado y proporcionar funciones básicas de la puerta de enlace basadas en la cadena de filtros, como: seguridad, monitoreo/indicadores y limitación de corriente.

11.2 Función

  • agente de dirección
  • Autenticación
  • control de flujo
  • fusible
  • Monitoreo de registros

11.3 ¿Dónde está la puerta de entrada en la arquitectura de microservicios?

Insertar descripción de la imagen aquí

11.4 Modelo asíncrono sin bloqueo de GateWay

¿Por qué Zuull volvió a salir de Gateway? ¿Por qué elegimos Gateway?

  1. Netflix no es muy confiable, Zuul 2.0 se retrasó y no se lanzó.

    1. Por un lado, debido a que Zuul 1.0 ha entrado en la etapa de mantenimiento y Gateway fue desarrollado por el equipo de Spring Cloud, es un producto hijo y confiable. Además, muchas funciones de Zuul son muy sencillas y cómodas de utilizar.
    2. Gateway se desarrolla en base a un modelo asincrónico sin bloqueo, por lo que no hay necesidad de preocuparse por el rendimiento. Aunque Netflix ya lanzó el último Zuul 2.x, Spring Cloud parece no tener planes de integración. Además, los componentes relacionados con Netflix han anunciado que han entrado en período de mantenimiento; me pregunto cuál será el futuro.
    3. Teniendo en cuenta todos los aspectos, Gateway es una opción de puerta de enlace ideal.
  2. SpringCloud Gateway tiene las siguientes características

    1. Construido sobre Spring Framework 5, Project Reactor y Spring Boot 2.0;
    2. Enrutamiento dinámico: capaz de coincidir con cualquier atributo de solicitud;
    3. Puede especificar Predicado y Filtro para rutas;
    4. Función de disyuntor Hystrix integrada;
    5. Integre la función de descubrimiento de servicios Spring Cloud;
    6. Predicados y filtros fáciles de escribir;
    7. Solicitar función de limitación de corriente;
    8. Admite la reescritura de rutas.
    9. La diferencia entre SpringCloud Gateway y Zuul
  3. Antes de la versión oficial de Spring Cloud Finchley, la puerta de enlace recomendada para Spring Cloud era Zuul proporcionada por Netflix.

    1. Zuul 1.x es una puerta de enlace API basada en el bloqueo de E/S.
    2. Zuul 1.x está basado en Servlet 2.5 y utiliza una arquitectura de bloqueo. No admite conexiones largas (como WebSocket). El patrón de diseño de Zuul es más similar a Nginx. Cada operación de E/S selecciona una ejecución del hilo de trabajo, y el hilo de solicitud se bloquea hasta que el trabajador El hilo se completa, pero la diferencia es que Nginx está implementado en C ++, Zuul está implementado en Java y la JVM en sí tendrá una carga más lenta por primera vez, lo que hará que el rendimiento de Zuul sea relativamente pobre.
    3. El concepto Zuul 2.x es más avanzado y quiere no bloquear y admitir conexiones largas basadas en Netty, pero Spring Cloud aún no lo ha integrado. El rendimiento de Zuul .x ha mejorado mucho en comparación con Zuul 1.x. En términos de rendimiento, según la prueba de referencia oficial, el RPS (solicitudes por segundo) de Spring Cloud Gateway es 1,6 veces mayor que el de Zuul.
    4. Spring Cloud Gateway se basa en Spring Framework 5, Project Reactor y Spring Boot2 y utiliza API sin bloqueo.
    5. Spring Cloud Gateway también es compatible con WebSocket y está estrechamente integrado con Spring para una mejor experiencia de desarrollo.

Modelo Zuul1.x

La versión Zuul integrada en Springcloud utiliza el contenedor Tomcat y utiliza el modelo de procesamiento tradicional Serviet IO.

¿Ciclo de vida del servlet? La gestión del ciclo de vida de los servlets se realiza mediante un contenedor de servlets.

Cuando se inicia el contenedor, construye un objeto servlet y llama al servlet init() para su inicialización;
cuando el contenedor se está ejecutando, acepta solicitudes y asigna un subproceso para cada solicitud (generalmente obtiene un subproceso inactivo del grupo de subprocesos) y luego llama al servicio. ); cuando el
contenedor se cierra, llama al servlet destroy () Destruye el servlet.

Desventajas del modelo anterior:

Servlet es un modelo de E/S de red simple. Cuando una solicitud ingresa al contenedor de Servlet, el contenedor de Servlet le vinculará un hilo. Este modelo es aplicable en escenarios donde la concurrencia no es alta. Sin embargo, una vez que la concurrencia es alta (como el uso de Jmeter para suprimir el problema), la cantidad de subprocesos aumentará y el costo de los recursos de los subprocesos será elevado (cambio de texto en línea, gran consumo de memoria), lo que afectará seriamente el tiempo de procesamiento de la solicitud. En algunos escenarios de negocios simples, no desea asignar un subproceso para cada solicitud. Solo se necesitan uno o unos pocos subprocesos para manejar solicitudes extremadamente concurrentes. En este escenario de negocios, el modelo de servlet no tiene ninguna ventaja.

Por lo tanto, Zuul 1. Por tanto, SpringCloud Zuul no puede deshacerse de las deficiencias del modelo de servlet.

Modelo de puerta de enlace

¿Qué es WebFlux?

Los marcos web tradicionales, como Struts2, SpringMVC, etc., se ejecutan en función de la API de Servlet y el contenedor de Servlet.

Pero después de Servlet3.1, existe soporte asincrónico sin bloqueo. WebFlux es un marco asincrónico sin bloqueo típico y su núcleo se implementa en base a API relacionadas con Reactor. En comparación con los marcos web tradicionales, puede ejecutarse en contenedores como Netty, Undertow y Servlet3.1. Programación funcional + sin bloqueo (Spring 5 debe permitirle usar Java 8).

Spring WebFlux es un nuevo marco reactivo introducido en Spring 5.0. A diferencia de Spring MVC, no necesita depender de Servlet API, es completamente asíncrono y sin bloqueo, y se basa en Reactor para implementar especificaciones de flujo reactivo.

11.5 Flujo de trabajo de puerta de enlace

11.5.1 Tres conceptos centrales

  1. Ruta: la ruta es el módulo básico para construir una puerta de enlace. Consta de ID, URI de destino, una serie de afirmaciones y filtros. Si la afirmación es verdadera, la ruta coincidirá;
  2. Predicado (Aserción): en referencia a java.util.function.Predicate de Java8, los desarrolladores pueden hacer coincidir todo en la solicitud HTTP (como los encabezados de la solicitud o los parámetros de la solicitud) y enrutar la solicitud si coincide con la afirmación;
  3. Filtro: se refiere a una instancia de GatewayFilter en el marco Spring. Usando filtros, las solicitudes se pueden modificar antes o después de enrutar la solicitud.

La solicitud web localiza el nodo de servicio real mediante algunas condiciones coincidentes. Y realice un control refinado antes y después de este proceso de reenvío.

el predicado es nuestra condición de coincidencia y el filtro puede entenderse como un interceptor omnipotente. Con estos dos elementos, más la uri de destino, se puede implementar una ruta específica.

11.5.2 Flujo de trabajo

Insertar descripción de la imagen aquí

El cliente realiza una solicitud a Spring Cloud Gateway. Luego busque la ruta que coincida con la solicitud en Gateway Handler Mapping y envíela a Gateway Web Handler.

Luego, el controlador envía la solicitud a nuestro servicio real para ejecutar la lógica empresarial a través de la cadena de filtro especificada y luego regresa.
Los filtros están separados por líneas de puntos porque pueden ejecutar la lógica empresarial antes ("pre") o después ("post") de enviar la solicitud de proxy.

Los filtros del tipo "pre" pueden realizar verificación de parámetros, verificación de permisos, monitoreo de tráfico, salida de registros, conversión de protocolos, etc. Los
filtros del tipo "post" pueden modificar el contenido de la respuesta y los encabezados de respuesta, y modificar los registros. etc. juegan un papel muy importante.

11.6 Construcción de la puerta de enlace

11.6.1 puerta de enlace-nube-gateway9527

11.6.2 Crear POM.XML

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-gateway-gateway9527</artifactId>

    <dependencies>
        <!--gateway-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <!--eureka-client-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

11.6.3 Crear aplicación.yml

Actualmente no queremos exponer el puerto 8001 y esperamos cubrir 8001 con una capa de 9527. Configure las reglas en
Si la ruta de acceso contiene la escrita, entonces el prefijo de dirección de acceso original se cambiará al configurado.routespredicateshost+端口uri


server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: http://localhost:8001          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

11.6.4 Crear clase de inicio

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

11.6.5 Pruebas

  • Inicio 7001
  • Inicio 8001: -pago-proveedor-nube8001
  • Iniciar puerta de enlace 9527
  • Instrucciones de acceso
    • Antes de agregar la puerta de enlace: http://localhost:8001/paid/get/1
    • Después de agregar la puerta de enlace: http://localhost:9527/paid/get/1
    • Ambos accesos son exitosos y devuelven el mismo resultado.

11.7 Configuración del enrutamiento dinámico (equilibrio de carga)

De forma predeterminada, Gateway creará una ruta dinámica basada en la lista de servicios registrada en el centro de registro y la reenviará según la ruta del nombre del microservicio en el centro de registro, implementando así la función de enrutamiento dinámico. ahora ha cambiado a, lo que indica que la función de equilibrio de carga de
Gateway uriestá http://localhost:8001habilitada lb://cloud-payment-service.
El uri de equilibrio de carga creado automáticamente por la puerta de enlace para nosotros en microservicios


server:
  port: 9527

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由

        - id: payment_routh2 #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/lb/**         # 断言,路径相匹配的进行路由

eureka:
  instance:
    hostname: cloud-gateway-service
  client: #服务提供者provider注册进eureka服务列表内
    service-url:
      register-with-eureka: true
      fetch-registry: true
      defaultZone: http://eureka7001.com:7001/eureka

11.8 Uso de predicados

Fábrica de predicados de ruta de Spring Cloud Gateway (Route Predicate Factories), la función de la fábrica de predicados de ruta es: si cumple con las condiciones del predicado, use la configuración de la ruta; de lo contrario, se ignorará. Mientras domines esta oración, será más fácil dominar la fábrica de predicados de enrutamiento.

fábrica de predicados
Después
Antes
Entre
Galleta
Encabezamiento
Anfitrión
Método
Camino
Consulta
Dirección remota

11.8.1 Después de fábrica

spring:
  application:
    name: cloud-gateway
  cloud:
    gateway:
      routes:
        - id: payment_routh #payment_route    #路由的ID,没有固定规则但要求唯一,建议配合服务名
          uri: lb://cloud-payment-service          #匹配后提供服务的路由地址
          predicates:
            - Path=/payment/get/**         # 断言,路径相匹配的进行路由
            - After=2021-08-18T21:49:21.011+08:00[Asia/Shanghai]

Significa que solo se puede acceder después de este período de tiempo; de lo contrario, el acceso será 404. La dirección de prueba es http://localhost:9527/paid/get/1.
El resto no se demostrará. Vaya a Spring Cloud Gateway- Fábricas de predicados de ruta Consulte este artículo.

11.9 Filtro

Los filtros de enrutamiento se pueden utilizar para modificar las solicitudes HTTP entrantes y las respuestas HTTP devueltas. Los filtros de enrutamiento solo pueden especificar rutas para su uso.

Spring Cloud Gateway tiene una variedad de filtros de enrutamiento integrados, todos los cuales son generados por la clase de fábrica de GatewayFilter para generar el
filtro de Spring Cloud Gateway:

  • ciclo vital:
    • pre
    • correo
  • Tipo (ver documentación oficial para más detalles)
    • GatewayFilter: hay 31 tipos
    • GlobalFilter: hay 10 tipos

GatewayFilter de uso común: AddRequestParameter GatewayFilter
GlobalFilter global personalizado:
Introducción a las dos interfaces principales :

  • Filtro global
  • Ordenado

Qué puedes hacer :

  • Registro global
  • Autenticación de puerta de enlace unificada

Ejemplo de código:
si accede al enlace sin el parámetro uname, no podrá acceder al enlace.
Método getOrder: carga el orden del filtro. Cuanto menor sea el valor de retorno, mayor será el orden de prioridad.

@Component
@Slf4j
public class MyLogGateWayFilter implements GlobalFilter,Ordered
{
    
    

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain)
    {
    
    
        log.info("***********come in MyLogGateWayFilter:  "+new Date());

        String uname = exchange.getRequest().getQueryParams().getFirst("uname");

        if(uname == null)
        {
    
    
            log.info("*******用户名为null,非法用户,o(╥﹏╥)o");
            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
            return exchange.getResponse().setComplete();
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder()
    {
    
    
        return 0;
    }
}

Acceder a http://localhost:9527/paid/get/1?uname=ZX es normal, no se puede
acceder a la página web http://localhost:9527/paid/get/1 y la consola imprime el registro.

12.Configuración

12.1 Función

Problemas de configuración que enfrentan los sistemas distribuidos

Microservicios significa dividir el negocio en una sola aplicación en subservicios. La granularidad de cada servicio es relativamente pequeña, por lo que habrá una gran cantidad de servicios en el sistema. Dado que cada servicio requiere la información de configuración necesaria para ejecutarse, es esencial una instalación de gestión de configuración dinámica y centralizada.

SpringCloud proporciona ConfigServer para resolver este problema. Cada uno de nuestros microservicios tiene su propia aplicación.yml, que puede administrar cientos de archivos de configuración...

Insertar descripción de la imagen aquí

qué es

SpringCloud Config proporciona soporte de configuración externa centralizada para microservicios en la arquitectura de microservicios. El servidor de configuración proporciona una configuración externa centralizada para todos los entornos de diferentes aplicaciones de microservicios.

Cómo jugar

SpringCloud Config se divide en dos partes : servidor y cliente .

  • El servidor, también llamado centro de configuración distribuida, es una aplicación de microservicio independiente que se utiliza para conectarse al servidor de configuración y proporcionar interfaces de acceso para que los clientes obtengan información de configuración, cifren/descifren información, etc.

  • El cliente administra los recursos de la aplicación y el contenido de configuración relacionado con el negocio a través del centro de configuración designado, y obtiene y carga información de configuración desde el centro de configuración al inicio. El servidor de configuración usa git para almacenar información de configuración de forma predeterminada, lo cual es útil para la administración de versiones de la configuración del entorno. y el contenido de configuración se puede administrar y acceder fácilmente a través de las herramientas del cliente git.

Qué puedes hacer

  • Gestione de forma centralizada los archivos de configuración
  • Diferentes configuraciones para diferentes entornos, actualizaciones de configuración dinámicas e implementación específica del entorno, como dev/test/prod/beta/release
  • Ajuste dinámicamente la configuración durante la operación. No es necesario escribir archivos de configuración en las máquinas donde se implementa cada servicio. El servicio extraerá uniformemente su propia información de configuración del centro de configuración.
  • Cuando la configuración cambia, no es necesario reiniciar el servicio para detectar los cambios de configuración y aplicar la nueva configuración.
    Exponga la información de configuración en forma de interfaz REST; simplemente actualícela accediendo a post/crul...

Integrar la configuración con GitHub

Dado que SpringCloud Config usa Git para almacenar archivos de configuración de forma predeterminada (hay otras formas, como admitir SVN y archivos locales), el más recomendado es Git y usa acceso http/https.

12.2 Configuración y prueba del servidor

Correspondiente al módulo Config Server en la figura anterior

12.2.1 Github crea un archivo de configuración

Bifurque https://github.com/zzyybs/springcloud-config directamente y luego cambie el uri de yml a la dirección después de la bifurcación.

12.2.2 Crear módulo ConfigCenterMain3344

12.2.3 Crear POM, YML, clase de inicio

<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-config-center-3344</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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-actuator</artifactId>
        </dependency>
    </dependencies>

</project>
server:
  port: 3344

spring:
  application:
    name:  cloud-config-center #注册进Eureka服务器的微服务名
  cloud:
    config:
      server:
        git:
          uri: https://github.com/Aerozb/springcloud-config.git #GitHub上面的git仓库名字
          username: github用户名
          password: github密码
        ####搜索目录
          search-paths:
            - springcloud-config
      ####读取分支
      label: master

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

Habilite la anotación del centro de configuración @EnableConfigServer

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

12.2.4 Pruebas

Visite http://127.0.0.1:3344/master/config-dev.yml
y descubra que se puede obtener el contenido interno

12.3 Configuración y prueba del cliente

12.3.1 arranque.yml

applicaiton.yml es un elemento de configuración de recursos a nivel de usuario.
bootstrap.yml está a nivel de sistema y tiene una prioridad más alta.

Spring Cloud creará un "Contexto Bootstrap" como Application Contextcontexto principal de la aplicación Spring. Durante la inicialización, Bootstrap Contextes responsable de cargar las propiedades de configuración desde fuentes externas y analizar las configuraciones. Los dos contextos comparten uno obtenido desde el exterior Environment.

BootstrapLas propiedades tienen alta prioridad y, de forma predeterminada, la configuración local no las anula. Bootstrap contexty Application Contexttienen convenciones diferentes, por lo que bootstrap.ymlse agregó un nuevo archivo para garantizar la separación Bootstrap Contextde Application Contextla configuración.

Es fundamental cambiar el archivo application.yml en el módulo Cliente a bootstrap.yml,
porque bootstrap.yml se carga antes que application.yml. bootstrap.yml tiene mayor prioridad que application.yml
Insertar descripción de la imagen aquí

12.3.2 Crear módulo cloud-config-client-3355

12.3.3 Crear POM, YML, clase de inicio, clase de acceso

<?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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-config-client-3355</artifactId>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</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-actuator</artifactId>
        </dependency>
    </dependencies>

</project>

arranque.yml

server:
  port: 3355

spring:
  application:
    name: config-client
  cloud:
    #Config客户端配置
    config:
      label: master #分支名称
      name: config #配置文件名称
      profile: dev #读取后缀名称   上述3个综合:master分支上config-dev.yml的配置文件被读取http://config-3344.com:3344/master/config-dev.yml
      uri: http://localhost:3344 #配置中心地址

#服务注册到eureka地址
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

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

Visitar el centro de configuración

@RestController
@RefreshScope
public class ConfigClientController
{
    
    
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/configInfo")
    public String getConfigInfo()
    {
    
    
        return configInfo;
    }
}

12.3.3 Pruebas

Primero visite el centro de configuración http://127.0.0.1:3344/master/config-dev.yml para ver si tiene éxito, de la siguiente manera

config:
  info: master branch,springcloud-config/config-dev.yml version=1

Al acceder al cliente http://localhost:3355/configInfo , se muestra el mismo contenido arriba, lo que indica éxito.

Se implementó con éxito el acceso del cliente 3355 a SpringCloud Config 3344 para obtener información de configuración a través de GitHub. Las preguntas pueden surgir en cualquier momento.

Problema de actualización dinámica de la configuración distribuida

  • La operación y mantenimiento de Linux modifica el contenido del archivo de configuración en GitHub para realizar ajustes
  • Actualice 3344 y descubra que el centro de configuración de ConfigServer respondió inmediatamente ( sin cambios en mi prueba )
  • Se actualizó 3355 y se descubrió que el cliente ConfigClient no respondió.
  • 3355 No hay cambios a menos que reinicie o recargue
  • ¿Es tan difícil que cada vez que operación y mantenimiento modifican el archivo de configuración, es necesario reiniciar el cliente?

12.4 Actualización dinámica del cliente

12.4.1 POM introduce la supervisión del actuador

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

12.4.2 Modificar YML para exponer el puerto de monitoreo

# 暴露监控端点
management:
  endpoints:
    web:
      exposure:
        include: "*"

12.4.3 Modificar controlador

Agregar @RefreshScope

12.4.4 Modificar el archivo de configuración github config-dev.yml

12.4.5 Cliente de acceso

http://localhost:3355/configInfo
descubrió que todavía no ha cambiado

12.4.6 Iniciar activamente una solicitud para notificar al cliente que se ha actualizado

curl -X POST "http://localhost:3355/actuator/refresh"

La ventaja es que no es necesario reiniciar el cliente.

12.4.7 Acceder nuevamente al cliente

Descubrió que el cambio ha sido exitoso.

13.Centro de configuración y registro de servicios de Nacos

13.1 ¿Por qué se llama Nacos?

Las primeras cuatro letras son las dos primeras letras de Nombre y Configuración respectivamente, y la última s es Servicio.

13.2 ¿Qué es?

  • Una plataforma dinámica de descubrimiento de servicios, gestión de configuración y gestión de servicios que facilita la creación de aplicaciones nativas de la nube.
  • Nacos: Servicio de configuración y nombres dinámicos
  • Nacos es una combinación de centro de registro + centro de configuración -> Nacos = Eureka+Config+Bus

13.3 ¿Qué puedes hacer?

  • Reemplazar a Eureka como centro de registro de servicios
  • Reemplazar Config como centro de configuración de servicio

13.4 Descargar, instalar, iniciar

  1. https://nacos.io/zh-cn/index.html, haga clic en V1.XX en el medio para descargar la versión en su página.
  2. Abrir bin/startup.cmd
  3. Modifique el clúster set MODE="cluster"a una sola máquina set MODE="standalone"; de lo contrario, se informará un error al inicio
  4. Ejecute inicio.cmd

13.5 Crear el módulo proveedor de servicios cloudalibaba-provider-paid9001

13.5.1 Agregar dependencias al POM principal

			<dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

13.5.2 Este 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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-provider-payment9001</artifactId>

    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>

13.5.3 YML

Indica que el proveedor de pagos de nacos está registrado en nacos: localhost:8848

server:
  port: 9001

spring:
  application:
    name: nacos-payment-provider
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #配置Nacos地址

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

13.5.4 Inicio principal

Utilice la anotación @EnableDiscoveryClient para registrar un microservicio en el centro de registro de nacos

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

13.5.5 Clase empresarial (capa de control)

@RestController
public class PaymentController
{
    
    
    @Value("${server.port}")
    private String serverPort;

    @GetMapping(value = "/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id)
    {
    
    
        return "nacos registry, serverPort: "+ serverPort+"\t id"+id;
    }
}

13.5.6 Pruebas

  1. Iniciar nubealibaba-proveedor-pago9001
  2. Verifique la consola de nacos y descubra que se ha registrado en nacos.Insertar descripción de la imagen aquí
  3. Visite http://localhost:9001/paid/nacos/1 y muestre la información devuelta, lo que indica el éxito.

13.6 Crear proveedor de servicios cloudalibaba-provider-paid9002 para demostrar el equilibrio de carga de nacos

Los pasos de creación son los mismos que 9001.

13.7 Crear nube de consumidor de serviciosalibaba-consumer-nacos-order83

13.7.1 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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-consumer-nacos-order83</artifactId>

    <dependencies>
        <!--SpringCloud ailibaba 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>
        <!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>

13.7.2 años

servidor:
puerto: 83

primavera:
aplicación:
nombre: nacos-order-consumer
nube:
nacos:
descubrimiento:
dirección-servidor: localhost:8848

13.7.3 Clase de inicio

Preste atención a las anotaciones, habilite openFeign y el descubrimiento de servicios.

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

13.7.4 Servicio de pago de llamadas remotas PaymentFeignService

@FeignClient("nacos-payment-provider")
public interface PaymentFeignService {
    
    

    @GetMapping(value = "/payment/nacos/{id}")
    public String getPayment(@PathVariable("id") Integer id);
}

13.7.5 Capa de control

@RestController
public class OrderNacosController
{
    
    
    @Resource
    PaymentFeignService paymentFeignService;

    @GetMapping(value = "/consumer/payment/nacos/{id}")
    public String paymentInfo(@PathVariable("id") Integer id)
    {
    
    
        return paymentFeignService.getPayment(id);
    }

}

13.7.6 Pruebas

  1. Iniciar PagoMain9001, PagoMain9002, OrdenNacosMain83
  2. Visite continuamente http://localhost:83/consumer/paid/nacos/13

Los resultados de la devolución son los siguientes:

nacos registry, serverPort: 9001 id13
nacos registry, serverPort: 9002 id13

13.8 Cambio entre los modos AP y CP

C significa que los datos vistos por todos los nodos al mismo tiempo son consistentes, y la definición de A es que todas las solicitudes recibirán respuestas.

¿Cuándo eliges qué modo usar?
En términos generales,
si no es necesario almacenar información de nivel de servicio y la instancia de servicio está registrada a través de nacos-client y puede mantener informes de latidos, entonces puede elegir el modo AP. Los servicios principales actuales, como Spring Cloud y Dubbo, son todos adecuados para el modo AP. El modo AP debilita la coherencia en aras de la posibilidad del servicio, por lo que el modo AP solo admite el registro de instancias temporales.

Si necesita editar o almacenar información de configuración a nivel de servicio, entonces se requiere CP y los servicios K8S y DNS son adecuados para el modo CP.
El modo CP admite el registro de instancias persistentes. En este momento, el protocolo Raft se utiliza como modo operativo del clúster. En este modo, el servicio debe registrarse antes de registrar la instancia. Si el servicio no existe, se devolverá un error. .

curl -X PUT '$NACOS_SERVER:8848/nacos/v1/ns/operator/switches?entry=serverMode&value=CP'

13.9 Crear centro de configuración cloudalibaba-config-nacos-client3377 Demostración de cómo obtener la configuración

13.9.1 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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-config-nacos-client3377</artifactId>

    <dependencies>
        <!--nacos-config-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <!--nacos-discovery-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--web + actuator-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
    </dependencies>

</project>

13.9.2 arranque.yml,aplicación.yml

Nacos es lo mismo que springcloud-config. Al inicializar el proyecto, debe asegurarse de que la configuración se extraiga primero del centro de configuración. Solo
después de extraer la configuración se puede garantizar el inicio normal del proyecto.

Hay un orden de prioridad para cargar archivos de configuración en springboot, bootstrap tiene mayor prioridad que la aplicación

arranque.yml

server:
  port: 3377

spring:
  application:
    name: nacos-config-client
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
      config:
        server-addr: localhost:8848 #Nacos作为配置中心地址
        file-extension: yaml #指定yaml格式的配置

aplicación.yml

spring:
  profiles:
    active: dev # 表示开发环境

13.9.3 Clase de inicio

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

13.9.4 Capa de control

Actualice automáticamente la configuración a través de la anotación nativa de Spring Cloud @RefreshScope:

@RestController
@RefreshScope //支持Nacos的动态刷新功能。
public class ConfigClientController
{
    
    
    @Value("${config.info}")
    private String configInfo;

    @GetMapping("/config/info")
    public String getConfigInfo() {
    
    
        return configInfo;
    }
}

13.9.5 Agregar información de configuración en nacos

Insertar descripción de la imagen aquí
En Nacos Spring Cloud, el formato completo de dataId es el siguiente:

${
    
    prefix}-${
    
    spring.profiles.active}.${
    
    file-extension}
  • El prefijo tiene por defecto el valor de spring.application.name y también se puede configurar a través del elemento de configuración spring.cloud.nacos.config.prefix.
  • spring.profiles.active es el perfil correspondiente al entorno actual. Para obtener más información, consulte la documentación de Spring Boot. Nota: Cuando spring.profiles.active está vacío, el conector correspondiente no existirá y el formato de empalme de dataId se convierte en prefijo {prefijo}.prefijo . _ _ _ _ {extensión de archivo}
  • file-exetension es el formato de datos del contenido de configuración, que se puede configurar a través del elemento de configuración spring.cloud.nacos.config.file-extension. Actualmente, solo se admiten propiedades y tipos yaml.

13.9.6 Pruebas

  1. Visita http://localhost:3377/config/info
  2. Se descubrió que la configuración completa se obtuvo con éxito.
  3. Vaya a nacos para modificar la configuración, actualice el enlace y descubra que se ha actualizado.

14 centinela

14.1 Introducción

A medida que los microservicios se vuelven más populares, la estabilidad entre servicios y servicios se vuelve cada vez más importante. Sentinel es un componente de gestión de tráfico para una arquitectura de servicios heterogéneos distribuidos en varios idiomas. Utiliza principalmente el tráfico como punto de entrada, cubriendo el enrutamiento del tráfico, el control del tráfico, la configuración del tráfico, la degradación del disyuntor, la protección adaptativa contra sobrecargas del sistema, la protección del tráfico en puntos calientes, etc. Dimensión para ayudar a los desarrolladores a garantizar la estabilidad de los microservicios.
Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

14.2 Iniciar la consola

Descargue el paquete JAR de la consola.
Inicie: java -jar sentinel-dashboard-XXX.jar
visite: http://127.0.0.1:8080/La
contraseña de cuenta predeterminada es. Si sentinel
necesita cambiar la contraseña del puerto o algo así, consulte el
Insertar descripción de la imagen aquí
sitio web oficial. Estas páginas de configuración se mostrarán solo cuando hay solicitudes, lo cual es una carga diferida.

14.3 Crear módulo cloudalibaba-sentinel-service8401

14.3.1 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">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloudalibaba-sentinel-service8401</artifactId>


    <dependencies>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>

    </dependencies>

</project>

14.3.2 año

server:
  port: 8401

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719

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

14.3.3 Inicio principal

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

14.3.4 FlowLimitController de clase empresarial

@RestController
public class FlowLimitController
{
    
    

    @GetMapping("/testA")
    public String testA()
    {
    
    
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
    
    
        return "------testB";
    }
}

14.3.5 Iniciar, acceder a testA, ir a la consola para ver

14.4 Reglas de control de flujo

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
Hablemos del significado de las opciones.

  1. QPS + falla directa + rápida : cuando el umbral de una sola máquina se establece en 3, significa que m solo procesa 3 solicitudes por segundo y el resto devolverá directamente la falla.Blocked by Sentinel (flow limiting)

  2. QPS+Calentamiento+Fallo rápido : el umbral de una sola máquina se establece en 10. Cuando el calentamiento es 5, significa que el umbral es 3 (10/3) en los primeros 5 segundos desde la primera solicitud, y luego el el umbral pasa a ser 10.
    Por ejemplo: cuando se enciende el sistema de venta flash, habrá mucho tráfico, lo que es muy probable que acabe con el sistema. El método de precalentamiento consiste en proteger el sistema dejando entrar el tráfico lentamente y aumentando lentamente el umbral hasta el valor establecido valor umbral.

  3. QPS + directo + velocidad uniforme : este método controla estrictamente el intervalo de tiempo entre el paso de las solicitudes, es decir, permite que las solicitudes pasen a una velocidad uniforme, que corresponde al algoritmo del depósito con fugas.
    La función de este método se muestra en la siguiente figura:
    Insertar descripción de la imagen aquíEste método se utiliza principalmente para manejar el tráfico en ráfagas intermitentes, como las colas de mensajes. Imagine un escenario en el que una gran cantidad de solicitudes llegan en un segundo determinado y están inactivas durante los siguientes segundos. Esperamos que el sistema pueda procesar gradualmente estas solicitudes durante el siguiente período de inactividad en lugar de rechazarlas directamente en el primer segundo. .
    Simplemente deje que las solicitudes se pongan en cola y se procesen una por una.

  4. QPS + asociación + falla rápida : Insertar descripción de la imagen aquí
    significa que cuando el acceso a testB alcanza el umbral, el acceso a testA al mismo tiempo devolverá directamente información de falla.

14.5 Reglas de degradación

14.5.1 Definición de términos

Insertar descripción de la imagen aquí

RT (tiempo de respuesta promedio, segundos, fórmula de cálculo = tiempo total de solicitud/número de solicitudes) El
tiempo de respuesta promedio excede el umbral y las solicitudes aprobadas dentro de la ventana de tiempo >=5, la degradación se activa después de que se cumplan ambas condiciones al mismo tiempo tiempo.
El disyuntor se cierra después del período de ventana.
El RT máximo es 4900 (los más grandes deben pasar -Dcsp.sentinel.statistic.max.rt=XXXX para que surtan efecto)

Proporción anormal (segundo nivel)
QPS >= 5 y la proporción anormal (estadísticas de segundo nivel) excede el umbral, se activa la degradación; una vez finalizada la ventana de tiempo, la degradación se desactiva

Cuando el número de excepciones (nivel de minutos)
excede el umbral, se activa la degradación; una vez finalizado el período de tiempo, se desactiva la degradación.

14.5.2 Descripción

La degradación del disyuntor Sentinel limitará la llamada de este recurso cuando un recurso en el enlace de llamada esté en un estado inestable (como tiempo de espera de llamada o aumento anormal de la proporción), de modo que la solicitud
falle rápidamente y evite afectar otros recursos y causar degradación. error.

Cuando se degrada un recurso, las llamadas al recurso se desconectarán automáticamente dentro del siguiente período de degradación (el comportamiento predeterminado es generar una DegradeException).

14.5.3 RT (tiempo de respuesta promedio de segundo nivel, fórmula de cálculo = tiempo total de solicitud/número de solicitudes)

Insertar descripción de la imagen aquí

Insertar descripción de la imagen aquí
prueba

@GetMapping("/testD")
public String testD()
{
    
    
    //暂停几秒钟线程
    try {
    
     TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) {
    
     e.printStackTrace(); }
    log.info("testD 测试RT");
    return "------testD";
}

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
Según la configuración anterior,

Siempre hay 10 subprocesos (más de 5) llamando a testD en un segundo. Esperamos que esta tarea se procese en 200 milisegundos.
Si no se completa en 200 milisegundos, el disyuntor se abrirá en la siguiente ventana de tiempo de 1 segundo. (Fusible disparado) El microservicio no está disponible, se disparó el fusible y se cortó la energía.

Más tarde detuve jmeter y no hubo una cantidad tan grande de visitas, se apagó el disyuntor (se restableció el fusible) y los microservicios se restauraron correctamente.

14.5.4 Proporciones anormales

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

@GetMapping("/testD")
public String testD()
{
    
    
    log.info("testD 测试RT");
    int age = 10/0;
    return "------testD";
}

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí
De acuerdo con la configuración anterior, si accede solo, se informará un error una vez (int age = 10/0) ​​y se producirá un error una vez que lo ajuste. Después de abrir jmeter, puede enviar solicitudes con alta concurrencia directamente
. y múltiples llamadas cumplirán nuestras condiciones de configuración.
El disyuntor se enciende (el fusible se dispara), el microservicio ya no está disponible y el error ya no se informa pero el servicio se degrada.

14.5.5 Números de excepción

Insertar descripción de la imagen aquí
Insertar descripción de la imagen aquí

14.6 Límite actual de la clave de punto de acceso

14.6.1 ¿Qué es un punto de acceso?

Los puntos de acceso son datos a los que se accede con frecuencia. Muchas veces queremos contar o limitar los datos de TopN con la frecuencia de acceso más alta en determinados datos de puntos de acceso y realizar limitaciones actuales u otras operaciones en su acceso.
Insertar descripción de la imagen aquí

14.6.2 Uso

El método de encubrimiento
se divide en predeterminado del sistema y definido por el cliente. En el
caso anterior, después del problema del límite de flujo de salida, se utilizó el mensaje predeterminado del sistema Sentinel: Bloqueado por Sentinel (limitación de flujo). ¿
Podemos personalizarlo? Similar para hystrix, un método determinado Si algo sale mal, ¿encuentra el método de degradación correspondiente?
Conclusión
de HystrixCommand a @SentinelResource

    @GetMapping("/testHotKey")
    @SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
    public String testHotKey(@RequestParam(value = "p1", required = false) String p1,
                             @RequestParam(value = "p2", required = false) String p2) {
    
    
        //int age = 10/0;
        return "------testHotKey";
    }

    public String deal_testHotKey(String p1, String p2, BlockException exception) {
    
    
        return "------deal_testHotKey,o(╥﹏╥)o";  //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
    }

El modo de limitación actual solo admite el modo QPS y está codificado. (Esto se llama punto de acceso)
@SentinelResourceEl índice del parámetro del método de la anotación, 0 representa el primer parámetro, 1 representa el segundo parámetro, y así sucesivamente. El
umbral de una sola máquina y la duración de la ventana estadística indican que si el tiempo de la ventana excede el umbral , el flujo será limitado.
La captura de pantalla anterior muestra que si el primer parámetro tiene un valor, el QPS por segundo es 1. Si excede el límite actual, se llama al método de soporte dealHandler_testHotKey después del límite actual.

El acceso a http://localhost:8401/testHotKey?p1=abc fallará si alcanza el umbral QPS.
Sin embargo, el acceso simultáneo a http://localhost:8401/testHotKey?p2=abc no funcionará porque no está en el configuración La configuración que se escribe es el parámetro 0.

14.6.3 Casos especiales

Después de más de 1 segundo, el límite actual se limitará inmediatamente después de alcanzar el umbral 1. Esperamos que cuando el parámetro p1 sea un valor especial, su valor límite actual será diferente del habitual. Si el valor de p1 es igual a 5 , su valor límite actual será diferente. El umbral puede llegar a 3.
Insertar descripción de la imagen aquí
Visite http://localhost:8401/testHotKey?p1=5 . Cuando p1 es igual a 5, el umbral se convierte en 200.
Visite http://localhost:8401 /testHotKey?p1=3 . Cuando p1 no es igual a 5., el umbral se establece en 3.

14.7 @SentinelResource

Anteriormente @SentinelResource, para personalizar la información de excepción devuelta, era necesario escribir el método de procesamiento correspondiente en cada clase, lo cual es muy inconveniente, de la siguiente manera

  1. El valor predeterminado del sistema no refleja nuestros propios requisitos comerciales.
  2. Según las condiciones existentes, nuestro método de procesamiento personalizado se combina con el código comercial, que no es intuitivo.
  3. Agregar una cobertura a cada método comercial aumentará la sobrecarga del código.
  4. No se refleja un enfoque globalmente unificado.

Resuelto de la siguiente manera

14.7.1 Lógica de procesamiento de limitación de corriente definida por el cliente

blockHandler : personaliza la configuración de infracción de la consola centinela y completa el método de procesamiento

/byResourceEspecifique el método handleException para manejar excepciones de infracción (debe escribirse en esta clase)
/rateLimit/customerBlockHandlerEspecifique el método handlerException2 de la clase CustomerBlockHandle para manejar
la clase empresarial

@RestController
public class RateLimitController {
    
    
    @GetMapping("/byResource")
    @SentinelResource(value = "byResource", blockHandler = "handleException")
    public CommonResult byResource() {
    
    
        return new CommonResult(200, "按资源名称限流测试OK", new Payment(2020L, "serial001"));
    }

    public CommonResult handleException(BlockException exception) {
    
    
        return new CommonResult(444, exception.getClass().getCanonicalName() + "\t 服务不可用");
    }

    @GetMapping("/rateLimit/byUrl")
    @SentinelResource(value = "byUrl")
    public CommonResult byUrl() {
    
    
        return new CommonResult(200, "按url限流测试OK", new Payment(2020L, "serial002"));
    }


    @GetMapping("/rateLimit/customerBlockHandler")
    @SentinelResource(value = "customerBlockHandler",
            blockHandlerClass = CustomerBlockHandler.class,
            blockHandler = "handlerException2")
    public CommonResult customerBlockHandler() {
    
    
        return new CommonResult(200, "按客戶自定义", new Payment(2020L, "serial003"));
    }
}

Clase de manejo de fallas personalizada

public class CustomerBlockHandler {
    
    
    public static CommonResult handlerException(BlockException exception) {
    
    
        return new CommonResult(4444, "按客戶自定义,global handlerException----1");
    }

    public static CommonResult handlerException2(BlockException exception) {
    
    
        return new CommonResult(4444, "按客戶自定义,global handlerException----2");
    }
}

Configuración de la consola Sentinel:
Insertar descripción de la imagen aquí
visitehttp ://127.0.0.1:8401 /rateLimit/customerBlockHandler/Cuando se excede el umbral QPS, se descubre que se devuelve información de excepción personalizada.

14.8 Función del disyuntor de servicio

14.8.1 Crear módulo proveedor cloudalibaba-provider-paid9003/9004

Consulte el código fuente de git para conocer el código. No lo escribiré aquí.

14.8.2 Crear nube de consumidoralibaba-consumer-nacos-order84

@SentinelResourceEl significado de los atributos en

  • respaldo : se utiliza para proporcionar lógica de procesamiento de respaldo cuando se lanza una excepción. La función alternativa puede manejar todo tipo de excepciones (excepto los tipos de excepción excluidos en excepcionesToIgnore).
    Existen requisitos para la ubicación de la función alternativa y debe estar en la misma clase que el método original, pero según los requisitos reales, debemos colocarla en otras clases. @SentinelResource proporciona un objeto Class que especifica la clase correspondiente a través de fallbackClass y agrega una función estática; de lo contrario, no se puede analizar.
  • excepcionesToIgnore : cuando se configuran tanto el respaldo como el blockHandler, visite http://localhost:84/consumer/fallback/1

Fallback gestiona las excepciones de ejecución de Java. blockHandler gestiona la configuración de infracción de la consola de Sentinel.
Si se configuran tanto blockHandler como el respaldo, solo se ingresará la lógica de procesamiento de blockHandler cuando se genere una BlockException debido a una degradación de limitación actual.

Todos se utilizan para solicitudes ordinarias @FeignClienty también tienen un fallbackatributo que también se utiliza para manejar excepciones.

@RestController
@Slf4j
public class CircleBreakerController {
    
    
    public static final String SERVICE_URL = "http://nacos-payment-provider";

    @Resource
    private RestTemplate restTemplate;
    //==================OpenFeign
    @Resource
    private PaymentService paymentService;

    @RequestMapping("/consumer/fallback/{id}")
    //@SentinelResource(value = "fallback") //没有配置
//    @SentinelResource(value = "fallback",fallback = "handlerFallback") //fallback只负责业务异常
//    @SentinelResource(value = "fallback",blockHandler = "blockHandler") //blockHandler只负责sentinel控制台配置违规
    @SentinelResource(value = "fallback", fallback = "handlerFallback", blockHandler = "blockHandler",
            exceptionsToIgnore = {
    
    IllegalArgumentException.class})
    public CommonResult<Payment> fallback(@PathVariable Long id) {
    
    
        CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/" + id, CommonResult.class, id);

        if (id == 4) {
    
    
            throw new IllegalArgumentException("IllegalArgumentException,非法参数异常....");
        } else if (result.getData() == null) {
    
    
            throw new NullPointerException("NullPointerException,该ID没有对应记录,空指针异常");
        }

        return result;
    }

    //本例是fallback
    public CommonResult handlerFallback(@PathVariable Long id, Throwable e) {
    
    
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(444, "兜底异常handlerFallback,exception内容  " + e.getMessage(), payment);
    }

    //本例是blockHandler
    public CommonResult blockHandler(@PathVariable Long id, BlockException blockException) {
    
    
        Payment payment = new Payment(id, "null");
        return new CommonResult<>(445, "blockHandler-sentinel限流,无此流水: blockException  " + blockException.getMessage(), payment);
    }

    @GetMapping(value = "/consumer/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id) {
    
    
        return paymentService.paymentSQL(id);
    }
}

Al acceder a http://localhost:84/consumer/paidSQL/1, utiliza fegin para llamar al proveedor 9003/9004, que se agrega fallback. Cuando solo 9003 está habilitado, acceder a http://localhost:84/consumer/paidSQL/1 es normal.

En este momento, si el proveedor de microservicios 9003 se cierra deliberadamente y se accede nuevamente, se degradará automáticamente y no se consumirá, esto es para llamar al método en PaymentFallbackService.

Si no se agrega fallback, la página de error se devolverá directamente.
Nota: Si desea que esta propiedad surta efecto, debe agregar el marco Sentinel (cualquier marco fusible servirá). De lo contrario, no será válido. También debe agregar la configuración. .

# 激活Sentinel对Feign的支持
feign:
  sentinel:
    enabled: true
@FeignClient(value = "nacos-payment-provider", fallback = PaymentFallbackService.class)
public interface PaymentService {
    
    
    @GetMapping(value = "/paymentSQL/{id}")
    public CommonResult<Payment> paymentSQL(@PathVariable("id") Long id);
}
@Component
public class PaymentFallbackService implements PaymentService {
    
    
    @Override
    public CommonResult<Payment> paymentSQL(Long id) {
    
    
        return new CommonResult<>(44444, "服务降级返回,---PaymentFallbackService", new Payment(id, "errorSerial"));
    }
}

14.9 Persistencia de reglas

14.9.1 ¿Qué es?

Primero debemos saber: después de configurar las reglas en Sentinel Dashboard y reiniciar la aplicación, se perderán. Por lo tanto, en el entorno de producción real, es necesario configurar la implementación persistente de las reglas. Sentinel proporciona una variedad de datos diferentes fuentes para conservar la configuración de la regla, incluido file, redis, nacos,zk.

Esto requiere la gestión de reglas y la función de inserción de Sentinel Dashboard: gestión centralizada y reglas de inserción. Sentinel-core proporciona API e interfaces de extensión para recibir información. Los desarrolladores deben elegir una forma confiable de implementar reglas basadas en su propio entorno; al mismo tiempo, es mejor administrar las reglas de forma centralizada en la consola.

14.9.2 Cómo jugar

Persista las reglas de configuración de limitación actuales en Nacos. Siempre que actualice una dirección de descanso
de 8401, se podrán ver las reglas de control de flujo en la consola Sentinel. Siempre que no se elimine la configuración en Nacos, las reglas de control de flujo en Sentinel en 8401 seguirá siendo válido.

14.9.3 Pasos de configuración

1. Agregar dependencias

<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

2. Agregar la configuración de la fuente de datos de Nacos

spring:
  application:
    name: cloudalibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848 #Nacos服务注册中心地址
    sentinel:
      transport:
        dashboard: localhost:8081 #配置Sentinel dashboard地址
        port: 8719
      datasource: #Nacos数据源配置
        ds1:
          nacos:
            server-addr: localhost:8848
            dataId: cloudalibaba-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow

3. Agregar configuración en nacos

 
[
    {
    
    
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

resource:资源名称;
limitApp:流控针对的调用来源,若为 default 则不区分调用来源,默认值default
grade:阈值类型,0表示线程数,1表示QPS;
count:单机阈值;
strategy:流控模式,0表示直接,1表示关联,2表示链路;
controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;
clusterMode:是否集群。

Insertar descripción de la imagen aquí

14.9.4 Inspección

Inicie 8401, llame a http://localhost:8401/rateLimit/byUrl varias veces , actualice Sentinel y descubra que las reglas comerciales están ahí.
Insertar descripción de la imagen aquí
Detenga la aplicación y descubra que ya no están.
Insertar descripción de la imagen aquí
Inicie el acceso nuevamente y ahí están.

Supongo que te gusta

Origin blog.csdn.net/Fire_Sky_Ho/article/details/120363127
Recomendado
Clasificación