Есть ли способ создать отдельный клиент для каждого экземпляра Feign при использовании SpringCloud OpenFeign?

Мы можем указать клиента для экземпляра Feign при использовании OpenFeign, как показано ниже:

        his.fooClient = Feign.builder()
                .client(clientA)
                .target(FooClient.class, "https://PROD-SVC");

        this.adminClient = Feign.builder()
                .client(clientB)
                .target(FooClient.class, "https://PROD-SVC");

Но похоже, что нет способа сделать это, если использовать SpringCloud OpenFeign, все экземпляры Feign будут совместно использовать один клиент, так как мы не смогли настроить клиент для экземпляра Feign в соответствии с документацией: https://docs.spring.io/spring-cloud-openfeign/docs/current/reference/html/appendix.html.

Итак, как я могу достичь этой цели, используя SpringCloud OpenFeign?


person Collin    schedule 07.02.2021    source источник
comment
Один клиент настраивается SC OpenFeign. Сценарий, который вы описываете, будет новой функцией.   -  person OlgaMaciaszek    schedule 08.02.2021


Ответы (1)


Вы должны создать экземпляры Feign вручную, так же, как и при использовании OpenFeign.

Хорошие новости: вы можете использовать части конфигурации SpringCloud OpenFeign с @Import({FeignClientsConfiguration.class}).

Также с этим подходом можно использовать @RefreshScope. Нельзя использовать @RefreshScope с клиентами, созданными по аннотации @FeignClient.

Для простых случаев можно использовать FeignClientBuilder. Но у него очень плохие возможности настройки Feign.

Эти компоненты будут импортированы из FeignClientsConfiguration:
Decoder, Encoder, Contract, FeignLoggerFactory.

Contract используется для использования аннотаций Spring REST, таких как @PostMapping.

@Component
@RefreshScope
@Import({FeignClientsConfiguration.class})
class SomeClientFeign implements SomeClientApi {

    private static final boolean ALWAYS_FOLLOW_REDIRECTS = true;

    private final SomeConfig config;

    private final Decoder decoder;

    private final Encoder encoder;

    private final Contract contract;

    private final FeignLoggerFactory loggerFactory;

    private SomeClientApi clientApi;

    @Autowired
    public SomeClientFeign(SomeConfig config,
                           Decoder decoder, Encoder encoder,
                           Contract contract, FeignLoggerFactory loggerFactory) {
        this.config = config;
        this.decoder = decoder;
        this.encoder = encoder;
        this.contract = contract;
        this.loggerFactory = loggerFactory;
    }

    @PostConstruct
    private void createFeignClient() {
        Logger logger = loggerFactory.create(SomeClientApi.class);
        Logger.Level logLevel = config.isLogging() ? Logger.Level.FULL : Logger.Level.NONE;

        clientApi = Feign.builder()
                .client(client())
                .retryer(Retryer.NEVER_RETRY)
                .logger(logger)
                .logLevel(logLevel)
                .encoder(encoder).decoder(decoder).contract(contract)
                .options(requestOptions())
                .requestInterceptor(basicAuthRequestInterceptor())
                .target(SomeClientApi.class, config.getUrl());
    }

    private OkHttpClient client() {
        // to not recreate the client for each request, it is not important because the same dispatcher is used
        okhttp3.OkHttpClient client = new okhttp3.OkHttpClient.Builder()
                .connectTimeout(config.getConnectTimeoutMillis(), TimeUnit.MILLISECONDS)
                .readTimeout(config.getReadTimeoutMillis(), TimeUnit.MILLISECONDS)
                .followRedirects(ALWAYS_FOLLOW_REDIRECTS)
                .build();

        return new OkHttpClient(client);
    }

    private Request.Options requestOptions() {
        return new Request.Options(
                config.getConnectTimeoutMillis(), TimeUnit.MILLISECONDS,
                config.getReadTimeoutMillis(), TimeUnit.MILLISECONDS,
                ALWAYS_FOLLOW_REDIRECTS
        );
    }

    private BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new BasicAuthRequestInterceptor(config.getUsername(), config.getPassword());
    }

    @Override
    public SomeResponse create(SomeRequest request) {
        return clientApi.createSomething(request);
    }

}
person v.ladynev    schedule 13.02.2021