Spring Cloud Finge (llamada de servicio declarativo) explicación detallada

Introducción

Fingir puede ocultar la solicitud de descanso y pretender ser un controlador similar a Spring MVC. No hay necesidad de empalmar direcciones URL, empalmar parámetros, etc. por ti mismo, y deja todo en manos de Fingir.


Caso de inicio

  1. Importar dependencias en consumidores de servicios

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
    
  2. @EnableFeignClientsAgregar anotaciones a la clase de inicio

    El equilibrio de carga de la cinta se ha integrado automáticamente en Fingir, por lo que no es necesario que lo defina RestTemplateusted mismo .

    @SpringCloudApplication
    @EnableFeignClients		// 开启Feign注解
    public class ConsumerApplication {
          
          
        public static void main(String[] args) {
          
          
            SpringApplication.run(ConsumerApplication.class, args);
        }
    }
    
  3. Escribe un cliente fingido

    @FeignClient(value = "user-service")    // 添加FeignClient,指定服务ID
    public interface UserClient {
          
          
        /**
         * 声明一个feign的接口,它的实现是服务提供者的controller实现
         */
        @GetMapping("/user/{id}")
        User getById(@PathVariable("id") Long id);
    }
    
  4. Llamado en el código, use userClient para acceder a:

    @Autowired  // 注入UserClient
    private UserClient userClient;
    
    public User getUserById(@PathVariable long id) {
          
          
        User user = userClient.getById(id);
        return user;
    }
    

Explicación detallada de la anotación @FeignClient

  • La anotación @FeignClient solo se puede usar en la interfaz de interfaz. Fingir generará clases de implementación a través de un proxy dinámico.

    • @Target(ElementType.TYPE) modifica la anotación FeignClient, lo que indica que el objetivo de la anotación FeignClient está en la interfaz.
  • @FeignClient, declare que se trata de un cliente de Fingir y especifique el nombre del servicio a través del atributo de nombre/valor

  • El método definido en la interfaz adopta completamente las anotaciones SpringMVC, y Feign generará URL de acuerdo con las anotaciones y accederá para obtener los resultados.

  • La clase de inicio del servicio debe anotarse con @EnableFeignClients para que Fegin surta efecto.


Los atributos comunes de la anotación @FeignClient son los siguientes:

  • nombre / valor : especifique el nombre de FeignClient. Si el proyecto usa Ribbon (registro), el atributo de nombre se usará como el nombre del microservicio para el descubrimiento del servicio
  • url : generalmente se usa para la depuración, puede especificar manualmente la dirección llamada por @FeignClient. vacío por defecto
    • La url se puede obtener del archivo de configuración, si lo hay, se llamará a través de la url, si no, se llamará según el nombre del servicio. el formato esurl = "${xxx.xxx.xxx: }"
  • configuración : clase de configuración de Fingir, puede personalizar el codificador, decodificador, nivel de registro, contrato de Fingir y puede especificar diferentes configuraciones para cada cliente de Fingir
  • fallback : defina una clase de procesamiento tolerante a fallas. Cuando la llamada a una interfaz remota falla o se agota el tiempo de espera, se invocará la lógica tolerante a fallas de la interfaz correspondiente. La clase especificada por fallback debe implementar la interfaz marcada por @FeignClient
  • fallbackFactory : clase de fábrica, utilizada para generar ejemplos de clases de respaldo, a través de este atributo, se puede realizar la lógica tolerante a fallas común de cada interfaz y se puede reducir el código duplicado
  • ruta : defina el prefijo unificado del FeignClient actual, que se usa cuando server.context-path, server.servlet-path están configurados en el proyecto
  • decode404 : cuando se produce un error http 404, si el campo es verdadero, se llamará al decodificador para decodificar; de lo contrario, se lanzará una FeignException

Método de llamada:

  • Método 1: el proveedor de la interfaz está en el centro de registro

    Si el proveedor de servicios se ha registrado en el centro de registro, entonces el valor de nombre o valor es: el nombre de servicio del proveedor de servicios. Se debe especificar un nombre o valor para todos los clientes

    @FeignClient(value="run-product",fallback = ProductClientServiceFallBack.class)
    
  • Método 2: una sola interfaz http, el proveedor de la interfaz no está registrado en el centro de registro

    @FeignClient(name="runClient11111",url="localhost:8001")
    

    El valor de nombre aquí es: el nombre del cliente que llama

Los dos métodos anteriores se pueden llamar normalmente. name puede ser el nombre del servicio del registro, y cuando se agrega el atributo url, el valor del nombre no tiene nada que ver con el nombre del servicio del registro.


Configuración de Fingir Cliente

La configuración de fingir se amplía en función de la configuración de cinta y puede admitir la configuración de tiempo de espera de nivel de servicio, por lo que la configuración de fingir y la configuración de cinta tienen el mismo efecto.

El orden de prioridad de configuración de SpringCloud es el siguiente:

  • Fingir configuración local > Fingir configuración global > Configuración local de cinta > Configuración global de cinta
  • El orden de prioridad de los atributos del archivo de configuración y las clases de configuración es: configuración del atributo del archivo de configuración > configuración del código de la clase de configuración
feign:
  client:
    config:
      default:	# 全部服务配置
        connectTimeout: 5000	# 建立连接的超时时长,单位:毫秒。默认为1000
        readTimeout: 5000		# 指建立连接后从服务端读取到可用资源所用的超时时间,单位:毫秒。默认为1000
        loggerLevel: FULL		# 日志级别
        errorDecoder: com.example.SimpleErrorDecoder  # Feign的错误解码器,相当于代码配置方式中的ErrorDecoder
        retryer: com.example.SimpleRetryer  # 配置重试,相当于代码配置方式中的Retryer
        requestInterceptors: # 配置拦截器,相当于代码配置方式中的RequestInterceptor
          - com.example.FooRequestInterceptor
          - com.example.BarRequestInterceptor
        decode404: false	# 是否对404错误解码
        encode: com.example.SimpleEncoder
        decoder: com.example.SimpleDecoder
        contract: com.example.SimpleContract
      serverName:	# 单独给某⼀服务配置。serverName是服务名,使⽤的时候要⽤服务名替换掉这个
        connectTimeout: 5000
        readTimeout: 5000

Fingir solicitudes para agregar encabezados

Solución 1: agregue información de encabezados a la anotación @RequestMapping en el método

El atributo de la anotación @RequestMapping contiene una matriz de encabezados. Puede agregar los encabezados requeridos a la anotación @RequestMapping en el método especificado, que puede estar codificado o leer la configuración =

Del mismo modo, las anotaciones @PostMapping y @GetMapping del grupo @RequestMapping son aplicables

@FeignClient(name = "server",url = "127.0.0.1:8080")
public interface FeignTest {
    
    
    @RequestMapping(value = "/test",headers = {
    
    "app=test-app","token=${test-app.token}"})
    String test();
}

Solución 2: agregue información de encabezados a la anotación @RequestMapping en la interfaz

Si todos los métodos en la misma interfaz requieren los mismos encabezados, puede agregar encabezados a la anotación @RequestMapping en la interfaz para que los métodos de toda la interfaz se agreguen con los mismos encabezados.

@FeignClient(name = "server",url = "127.0.0.1:8080")
@RequestMapping(value = "/",headers = {
    
    "app=test-app","token=${test-app.token}"})
public interface FeignTest {
    
    
    @RequestMapping(value = "/test")
    String test();
}

Solución 3: use la anotación @Headers para agregar información de encabezados (no recomendado)

@FeignClient(name = "server",url = "127.0.0.1:8080")
@Headers({
    
    "app: test-app","token: ${test-app.token}"})
public interface FeignTest {
    
    
    @RequestMapping(value = "/test")
    String test();
}

Mirando la documentación oficial de openfeign, se encuentra que usa @Headers para agregar encabezados. La prueba encontró que no tuvo efecto . Spring Cloud usa su propio SpringMvcContract para analizar las anotaciones, por lo que debe implementar un contrato usted mismo para admitir las anotaciones de @Headers. Para una implementación específica, consulte (https://juejin.im/post/6844903961653149709)


Solución 4: personalice RequestInterceptor para agregar información de encabezados

Fingir proporciona una interfaz de interceptor RequestInterceptor, que puede interceptar solicitudes de fingir mediante la implementación de la interfaz RequestInterceptor.La interfaz proporciona un método apply() para implementar el método apply()

La implementación del método apply() para agregar encabezados directamente interceptará todas las solicitudes y agregará encabezados. Si no es necesario usar todas las solicitudes fingidas, no se recomienda este método.

@Component
public class FeignRequestInterceptor implements RequestInterceptor {
    
    

    @Value("${test-app.token}")
    private String token;
    
    @Override
    public void apply(RequestTemplate requestTemplate) {
    
    
        requestTemplate.header("app","test-app");//静态
        requestTemplate.header("token",token);//读配置
    }
}

Solución 5: personalice la implementación de RequestInterceptor para agregar datos dinámicos al encabezado

Ninguna de las soluciones anteriores es adecuada para poner datos dinámicos en encabezados. En escenarios generales, la información dinámica, como las firmas calculadas y los ID de usuario, a menudo puede necesitar configurarse en encabezados, por lo que se necesita una solución más completa. El esquema 1/2/3 no puede establecer valores dinámicos, y el esquema 4 puede establecer valores dinámicos, pero no distingue entre solicitudes. Por lo tanto, el esquema 5 se mejora sobre la base del esquema 4. La implementación específica es la siguiente:

En el código de llamada de solicitud, obtenga el objeto HttpServletRequest, encapsule el valor que debe agregarse a los encabezados en un mapa y colóquelo en el campo de atributos de HttpServletRequest.

    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = Objects.requireNonNull(attributes).getRequest();
    String signedMsg = getSignedMsg(reqJson); 		// 计算签名字符串
    Map<String, String> reqMap = new HashMap<>();
    reqMap.put("content-type", "application/json");	//常量字段
    reqMap.put("accessKey", accessKey);		//常量字段
    reqMap.put("signedMsg", signedMsg);		//动态计算/获取字段
    request.setAttribute("customizedRequestHeader", reqMap);

Obtenga la clave especificada en el campo de atributo del objeto HttpServletRequest en el RequestInterceptor personalizado y agregue todos los parámetros en el mapa correspondiente a la clave a los encabezados.

@Component
public class FeignRequestInterceptor implements RequestInterceptor {
    
    

    @Override
    public void apply(RequestTemplate requestTemplate) {
    
    
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();

        // 设置自定义header
        // 设置request中的attribute到header以便转发到Feign调用的服务
        Enumeration<String> reqAttrbuteNames = request.getAttributeNames();
        if (reqAttrbuteNames != null) {
    
    
            while (reqAttrbuteNames.hasMoreElements()) {
    
    
                String attrName = reqAttrbuteNames.nextElement();
                if (!"customizedRequestHeader".equalsIgnoreCase(attrName)) {
    
    
                    continue;
                }
                Map<String,String> requestHeaderMap = (Map)request.getAttribute(attrName);
                for (Map.Entry<String, String> entry : requestHeaderMap.entrySet()) {
    
    
                    requestTemplate.header(entry.getKey(), entry.getValue());
                }
                break;
            }
        }
    }
}

Equilibrio de carga (cinta)

Fingir en sí tiene dependencias de cinta integradas y configuración automática, y es compatible con cinta de forma predeterminada.

La cinta integrada de Fegin establece el tiempo de espera de la solicitud de forma predeterminada, que es de 1000 ms de forma predeterminada. Debido a que hay un mecanismo de reintento dentro de la cinta, una vez que se agote el tiempo, la solicitud se reiniciará automáticamente

Se puede modificar por configuración:

La configuración global usa ribbon.=

ribbon:
  ReadTimeout: 2500 	# 数据通信超时时长,单位:ms。默认为1000
  ConnectTimeout: 500 	# 连接超时时长,单位:ms。默认为1000
  OkToRetryOnAllOperations: false 	# 是否对所有的异常请求(连接异常和请求异常)都重试。默认为false
  MaxAutoRetriesNextServer: 1 		# 最多重试多少次连接服务(实例)。默认为1。不包括首次调用
  MaxAutoRetries: 0 	# 服务的单个实例的重试次数。默认为0。不包括首次调用
  NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule	# 切换负载均衡策略为随机

Especifique la configuración del servicio <nombre del servicio>.ribbon.=

serverName:	# 单独给某⼀服务配置。serverName是服务名,使⽤的时候要⽤服务名替换掉这个
  ribbon:
    connectTimeout: 5000
    readTimeout: 5000

mecanismo de tolerancia a fallas

soporte Hystrix

Fingir también tiene integración con Hystix de forma predeterminada, pero está desactivada de forma predeterminada. Debe habilitarse con los siguientes parámetros:

feign:
  hystrix:
    enabled: true	# 开启hystrix熔断机制
     
hystrix:
  command:
    default:	# 全局默认配置
      execution:	# 线程隔离相关
        timeout:
          enabled: true		# 是否给方法执行设置超时时间,默认为true。一般不改。
        isolation:
          strategy: THREAD	# 配置请求隔离的方式,这里是默认的线程池方式。还有一种信号量的方式semaphore,
          thread:
            timeoutlnMilliseconds: 10000	# 方式执行的超时时间,默认为1000毫秒,在实际场景中需要根据情况设置
      circuitBreaker:	# 服务熔断相关
        requestVolumeThreshold: 10			# 触发熔断的最小请求次数,默认20
        sleepWindowInMilliseconds: 10000	# 休眠时长,单位毫秒,默认是5000毫秒
        errorThresholdPercentage: 50		# 触发熔断的失败请求最小占比,默认50%
    serverName:	# 单独给某⼀服务配置
      execution:
        timeout:
          enabled: true
        isolation:
          strategy: THREAD
          thread:
            timeoutlnMilliseconds: 10000

Aviso:

  • El período de tiempo de espera de Hystix debe ser más largo que el tiempo total de reintento de Ribbon. De lo contrario, después de que el comando de Hystrix se agote, el comando se fusionará directamente y el mecanismo de reintento no tendrá ningún significado.

    Cinta: número total de reintentos = número de servidores accedidos * número máximo de reintentos para un solo servidor

    Es decir, el número total de reintentos = (1+MaxAutoRetriesNextServer)*(1+MaxAutoRetries)

    Tiempo de espera de Hystrix > (suma del tiempo de espera de la cinta) * número de reintentos

    Por lo tanto, se sugiere que el período de tiempo de espera de hystrix sea:

    ( ( 1+MaxAutoRetriesNextServer) * (1+MaxAutoRetries ) ) * (ReadTimeout + connectTimeout)

    • MaxAutoRetries: Configuración de cinta: el número de reintentos para una única instancia del servicio. No incluye primera llamada
    • MaxAutoRetriesNextServer: configuración de cinta: cuántas veces reintentar el servicio de conexión (instancia) como máximo. No incluye primera llamada
    • ReadTimeout: configuración de cinta: tiempo de espera de comunicación
    • connectTimeout: configuración de cinta: tiempo de espera de establecimiento de conexión

Soporte centinela

Sentinel puede proporcionar la función de aislamiento de semáforos a través del control de flujo del modo de número de subprocesos concurrentes. Y combinado con el modo de degradación de fusible basado en el tiempo de respuesta, puede degradar automáticamente cuando el tiempo de respuesta promedio de los recursos inestables es relativamente alto, evitando que demasiadas llamadas lentas ocupen el número concurrente y afecten a todo el sistema.

confiar

        <!--Sentinel-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

Habilite el soporte de Feign para Sentinel en el archivo de configuración

feign:
  sentinel:
    enabled: true

Cómo usar Fingir después de habilitar el soporte del mecanismo tolerante a fallas

Después de que Feign habilita la compatibilidad con el mecanismo tolerante a fallas de Hystrix o Sentinel, se puede usar de las siguientes dos maneras:

  • Solución 1: heredar directamente la interfaz tolerante a fallas e implementar una solución tolerante a fallas para cada método
  • Solución 2: implementar la interfaz FallbackFactory

Solución 1: heredar directamente la interfaz tolerante a fallas e implementar una solución tolerante a fallas para cada método

  1. Defina una clase como la clase de procesamiento de reserva. Herede directamente la interfaz tolerante a fallas e implemente una solución tolerante a fallas para cada método

    @Component
    public class UserClientFallback implements UserClient {
          
          
        @Override
        public User getById(Long id) {
          
          
            return new User(1L, "我是备份-feign", 18, new Date());
        }
    }
    
  2. Use el atributo alternativo en la anotación @FeignClient para especificar una clase de procesamiento tolerante a fallas personalizada

    @FeignClient(value = "user-service",fallback = UserClientFallback.class)
    public interface UserClient {
          
          
        @GetMapping("/user/{id}")
        User getById(@PathVariable("id") Long id);
    }
    
  3. verificación de prueba

    inserte la descripción de la imagen aquí


Solución 2: implementar la interfaz FallbackFactory. Puede obtener información de error de servicio específica, lo cual es conveniente para la resolución de problemas más adelante.

@FeignClient(value="34-SPRINGCLOUD-SERVICE-GOODS", fallbackFactory = GoodsRemoteClientFallBackFactory.class)
public interface GoodsRemoteClient {
    
    
    
    @RequestMapping("/service/goods")
    public ResultObject goods();
}
@Component
public class GoodsRemoteClientFallBackFactory implements FallbackFactory<GoodsRemoteClient> {
    
    

    @Override
    public GoodsRemoteClient create(Throwable throwable) {
    
    
        return new GoodsRemoteClient() {
    
    
            @Override
            public ResultObject goods() {
    
    
                String message = throwable.getMessage();	// message即为错误信息
                System.out.println("feign远程调用异常:" + message);
                return new ResultObject();
            }
        };
    }
}

solicitar compresión (fingir.compresión)

Spring Cloud Feign admite la compresión GZIP para solicitudes y respuestas para reducir la pérdida de rendimiento durante la comunicación. La función de compresión de solicitudes y respuestas se puede habilitar mediante los siguientes parámetros:

feign:
  compression:
    request:
      enabled: true
    response:
      enabled: true

También puede establecer el tipo de datos de la solicitud y el límite inferior del tamaño que activa la compresión. Solo se comprimirán las solicitudes que excedan este tamaño:

feign:
  compression:
    request:
      enabled: true
      mime-types: text/xml,application/xml,application/json
      min-request-size: 2048

nivel de registro

Pase logging.level.xx=debugpara establecer el nivel de registro. Sin embargo, esto no tiene ningún efecto en el cliente de Fegin. Debido a que @FeignClientel cliente modificado por la anotación creará una nueva instancia de Fegin.Logger cuando se le envíe por proxy, es necesario especificar el nivel de este registro adicionalmente.

Fingir admite 4 niveles de registro:

  • NINGUNO: no registra ninguna información de registro, que es el valor predeterminado.
  • BÁSICO: solo registra el método de solicitud, la URL, el código de estado de respuesta y el tiempo de ejecución
  • ENCABEZADOS: Sobre la base de BASIC, la información del encabezado de la solicitud y la respuesta se registra adicionalmente
  • COMPLETO: registre los detalles de todas las solicitudes y respuestas, incluida la información del encabezado, el cuerpo de la solicitud y los metadatos.

configuración global

Método 1: Implementación de las propiedades del archivo de configuración

feign:
  client:
    config:
      default:	# 将调用的微服务名称设置为default即为配置成全局
        loggerLevel: FULL

Método 1: implementación de código

//在启动类上为@EnableFeignClients注解添加defaultConfiguration配置
@EnableFeignClients(defaultConfiguration = FeignConfig.class)

Granular (especifique la configuración del servicio)

Método 1: Implementación del archivo de configuración

feign:
  client:
    config:
      server-1:		# 想要调用的微服务名称
        loggerLevel: FULL

Método 2: Implementación de código

1) Escriba una clase de configuración para definir el nivel de registro

@Configuration
public class FeignConfig {
    
    
    @Bean
    Logger.Level level(){
    
    
        return Logger.Level.FULL;
    }
}

2) Especifique la clase de configuración en FeignClient: (se puede omitir)

@FeignClient(value = "user-service", configuration = FeignConfig.class)
// 添加FeignClient,指定服务ID
public interface UserClient {
    
    
    @GetMapping("/user/{id}")
    User getById(@PathVariable("id") Long id);
}

Ejemplo de registro de fingir para cada visita:

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/footless_bird/article/details/125341786
Recomendado
Clasificación