Использование запросов построителя Feign не отправляет идентификатор трассировки, идентификатор диапазона дочерним клиентам, но использование оставшегося шаблона показывает все заголовки на дочерних клиентах.

Я делаю последовательный запрос, используя Feign Builder. x-b3-traceid,x-b3-spanid.. в названии запроса отсутствуют. Именно поэтому лог моего последнего клиента появляется на зипкине.

Я использую spring boot 2.4.2, spring cloud 2020.0.0, feign-core 10.10.1, feign-okhttp 10.10.1. Я пробовал spring-cloud-openfeign и добился желаемого результата. Но я не хочу использовать эту библиотеку. Здесь есть запросы при использовании Feign Builder и Rest Template. Я не вижу такого же журнала в zipkin.

Мое приложение Client1. Я отправляю запрос http://localhost:8082/

import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign2.Client2Feign;

import javax.servlet.http.HttpServletRequest;
@RestController
public class SampleController {

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private Client client;

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    @Bean
    public OkHttpClient okHttpClient(){
        return new OkHttpClient();
    }

    @GetMapping("/hello/feignBuilder")
    public String sayHelloFeignBuilder(HttpServletRequest httpServletRequest){
        logger.info("Send to request client2");
        Client2Feign client2Feign = Feign.builder()
                .client(client)
                .decoder(new Decoder.Default())
                .encoder(new Encoder.Default())
                .target(Client2Feign.class, "http://localhost:8082/");
       return client2Feign.sayHelloFeignBuilder();
    }

    @GetMapping("/hello/say")
    public String sayHelloFeignBuilder1(){
        return "Hello";
    }

    @GetMapping("/hello/rest")
    public String sayHelloRest(){
        System.out.println(tracer.currentSpan());
        logger.info("Inside rest 1");
        String baseUrl = "http://localhost:8082/sayHelloRest";
        String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
        logger.info("The response received by client2 is " + response);
        return response;
    }

}

Это yml моего приложения client1. Я использую тот же yml conf в других клиентских приложениях, где client2 и clint3. Изменяет только порт и имя приложения.


server:
  port: 8081
spring:
  application:
    name: euraka-client1
  zipkin:
    enabled: true
    service.name: euraka-client1
    sender.type: web
    base-url: http://localhost:9411
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka
  instance:
    preferIpAddress: true

Это мое приложение Feign at Client2.

import feign.RequestLine;

public interface Client2Feign {

    @RequestLine("GET /sayHelloBuilder")
    String sayHelloFeignBuilder();

}

Вот реализация ClientFeign2.

import org.springframework.web.bind.annotation.GetMapping;

import javax.servlet.http.HttpServletRequest;

public interface FeignBuilderController {

    @GetMapping("/sayHelloBuilder")
    String sayHelloBuilder(HttpServletRequest httpServletRequest);

    @GetMapping("/sayHelloRest")
    String sayHelloRest(HttpServletRequest httpServletRequest);
}
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign.Client3Feign;
import sample.feign2.Client2Feign;

import javax.servlet.http.HttpServletRequest;

@RestController
public class FeignBuilderControllerImpl implements FeignBuilderController{

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private Client client;

    @Bean
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    @Bean
    public OkHttpClient okHttpClient(){
        return new OkHttpClient();
    }

    @Override
    public String sayHelloBuilder(HttpServletRequest httpServletRequest) {
        logger.info("Send to request client3");
        Client3Feign client3Feign = Feign.builder()
                .client(client)
                .decoder(new Decoder.Default())
                .encoder(new Encoder.Default())
                .target(Client3Feign.class, "http://localhost:8083/");
        return client3Feign.sayHelloFeignBuilder3();
    }

    @Override
    public String sayHelloRest(HttpServletRequest httpServletRequest) {
        logger.info("Inside rest 2");
        String baseUrl = "http://localhost:8083/sayHelloRestClient3";
        String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
        logger.info("The response received by client3 is " + response);
        return response;
    }

Это мое приложение Feign at Client3.

import feign.RequestLine;

public interface Client3Feign {

    @RequestLine("GET /sayHelloBuilderClient3")
    String sayHelloFeignBuilder3();

}

Вот реализация Client3 Feign.

import javax.servlet.http.HttpServletRequest;

public interface FeignController3 {

    @GetMapping("/sayHelloBuilderClient3")
    String sayHello3(HttpServletRequest httpServletRequest);

    @GetMapping("/sayHelloRestClient3")
    String sayHelloRest3(HttpServletRequest httpServletRequest);
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;

@RestController
@RequestMapping
public class FeignController3Impl implements FeignController3 {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public String sayHello3(HttpServletRequest httpServletRequest) {
        logger.info("Response returned from client3");
        return "Hello from client3 using FeignClientBuilder";
    }

    @Override
    public String sayHelloRest3(HttpServletRequest httpServletRequest) {
        logger.info("Response returned from client3");
        return "Hello from client3 using RestClient";
    }
}

pom.xml из client3, и я использую client3 в client2/pom и так же, как client1.


<?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>oguzhan.example</groupId>
    <artifactId>client3</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.4.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-sleuth</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-sleuth-zipkin</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-core</artifactId>
        </dependency>
        <dependency>
            <groupId>io.github.openfeign</groupId>
            <artifactId>feign-okhttp</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>build-info</id>
                        <goals>
                            <goal>build-info</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <release>${java.version}</release>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

diff-feign-rest-image

feign-zipkin-img

имитировать-запрос-img

rstlet-rest-tmplte-img

остальное-zipkin-img


person oguzhanonder7506    schedule 12.02.2021    source источник


Ответы (1)


Проблема может быть связана с тем, что вы создаете сборщик Feign вручную с помощью Feign.builder() фабричного метода. Мы не можем обработать этот вызов. Вы должны создать bean-компонент (через SleuthFeignBuilder.builder) и внедрить его в свой код.

person Marcin Grzejszczak    schedule 15.02.2021
comment
Прежде всего, большое спасибо за ответ. К сожалению, этого не произошло. Я создал bean следующим образом. После того, как я введу его. @Bean public Feign.Builder builder(){ return Feign.builder(); } @Autowired private Feign.Builder builder; - person oguzhanonder7506; 15.02.2021
comment
Мы не упаковываем строителей. Оборачиваем все, что производит застройщик - person Marcin Grzejszczak; 15.02.2021
comment
Извините, Марчин, я не понимаю, как обернуть продукцию строителя. Также я пытаюсь использовать код ниже. @Bean public Client2Feign client2Feign(){ return Feign.builder() .client(client) .target(Client2Feign.class,"http://localhost:8082"); } - person oguzhanonder7506; 16.02.2021
comment
Марчин, теперь я ясно понял. Это было решено, когда я использовал SleuthFeignBuilder.builder. Спасибо. - person oguzhanonder7506; 01.03.2021
comment
Нет проблем. Можем ли мы пометить это как решенное, пожалуйста? - person Marcin Grzejszczak; 01.03.2021