feign-reactive
repository·develop·Indexed 20 days ago
https://github.com/playtikaoss/feign-reactiveA reactive, non-blocking implementation of the Feign declarative HTTP client designed for Spring WebFlux, Project Reactor, and RxJava. It provides a concise syntax for client-side APIs on top of Spring WebClient, Java 11 HttpClient, and Jetty. The library includes modules for Spring Cloud integration (Ribbon, Hystrix, CircuitBreaker, and LoadBalancer) and supports auto-configuration via @EnableReactiveFeignClients in Spring Boot.
What's inside feign-reactive
- feign-reactive is an implementation of Feign on top of Spring WebClient. It combines the concise syntax of Feign for writing client-side APIs with the fast, asynchronous, and non-blocking capabilities of Spring WebClient.
Available feign-reactive modules
developThe project is divided into several modules depending on your runtime and reactive library requirements:
feign-reactor-core: Base classes and interfaces for implementing alternative reactor Feign implementations.feign-reactor-webclient: Implementation based on Spring WebClient.feign-reactor-cloud: Spring Cloud implementation (supports Ribbon/Hystrix).feign-reactor-java11: Implementation based on Java 11 HttpClient (high performance).feign-reactor-rx2: Rx2 compatible implementation (depends onfeign-reactor-webclient).feign-reactor-rx3: Rx3 compatible implementation (depends onfeign-reactor-webclient).feign-reactor-jetty: Experimental Reactive Jetty client implementation. Offers higher reactivity by streaming request bodies and receiving responses before the request body is fully sent.feign-reactor-spring-cloud-starter: Single dependency for Spring Cloud applications (uses WebClient by default).feign-reactor-bom: Maven BOM for simplified dependency management.
Configure Timeouts
developTo configure connect and read timeouts, use
ReactiveOptions.Builderas part of your Reactive Feign configuration.Important: Ribbon request timeout properties are ignored when using reactive clients; you must use the
ReactiveOptions.Builderspecific to your reactive HTTP client implementation.How to use feign-reactive with RxJava2 or RxJava3
developFor RxJava users, define your Feign API interface where every method:
- May accept
Flowable,Observable,Single, orMaybeas a request body. - Must return
Flowable,Observable,Single, orMaybe.
Use
Rx2ReactiveFeignorRx3ReactiveFeignto build the client.@Headers({"Accept: application/json"}) public interface IcecreamServiceApi { @RequestLine("GET /icecream/flavors") Flowable<Flavor> getAvailableFlavors(); @RequestLine("POST /icecream/orders") @Headers("Content-Type: application/json") Single<Bill> makeOrder(IceCreamOrder order); @RequestLine("POST /icecream/bills/pay") @Headers("Content-Type: application/json") Single<Long> payBill(Bill bill); } // Build the client IcecreamServiceApi client = Rx2ReactiveFeign .builder() .target(IcecreamServiceApi.class, "http://www.icecreame.com"); // Execute nonblocking requests Flowable<Flavor> flavors = client.getAvailableFlavors();- May accept
How to use feign-reactive with Project Reactor
developTo use the Reactor-based implementation, define your Feign API interface where every method:
- May accept
org.reactivestreams.Publisheras a request body. - Must return
reactor.core.publisher.Monoorreactor.core.publisher.Flux.
Use
WebReactiveFeign(for WebClient),JettyReactiveFeign, orJava11ReactiveFeignto build the client.@Headers({ "Accept: application/json" }) public interface IcecreamServiceApi { @RequestLine("GET /icecream/flavors") Flux<Flavor> getAvailableFlavors(); @RequestLine("POST /icecream/orders") @Headers("Content-Type: application/json") Mono<Bill> makeOrder(IceCreamOrder order); @RequestLine("POST /icecream/bills/pay") @Headers("Content-Type: application/json") Mono<Void> payBill(Publisher<Bill> bill); } // Build the client IcecreamServiceApi client = WebReactiveFeign .<IcecreamServiceApi>builder() .target(IcecreamServiceApi.class, "http://www.icecreame.com"); // Execute nonblocking requests Flux<Flavor> flavors = client.getAvailableFlavors();- May accept
Use Cloud2 (CircuitBreaker + LoadBalancer)
developFor Spring Cloud 2.2.0+ environments, it is highly recommended to use the
cloud2module (CircuitBreaker + LoadBalancer) instead of the legacycloudmodule.Setup: Add the
feign-reactor-cloudmodule to your classpath and exclude the legacyfeign-reactor-cloud(if applicable/necessary for your dependency tree).Global Toggle Properties:
reactive.feign.loadbalancer.enabled: Disable loadbalancer configuration.reactive.feign.circuit.breaker.enabled: Disable circuit breaker configuration.
Configuration via Beans:
- LoadBalancer: Define a
ReactiveLoadBalancer.Factorybean in your client configuration. - CircuitBreaker: Use a
ReactiveFeignCircuitBreakerFactorybean, or aReactiveCircuitBreakerFactorycombined with aReactiveFeignCircuitBreakerCustomizerbean.
New Retry Properties (Cloud2): Unlike the legacy module,
LoadBalancerin Cloud2 does not have a direct retry configuration, but you can use:retryOnSame: Number of retries for the same server.retryOnNext: Number of retries for the next server.
Enable Spring Auto-Configuration
developYou can automatically configure reactive Feign clients as Spring beans by adding thefeign-reactor-spring-configurationmodule to your classpath.Enable Reactive Feign Clients in Spring Boot
developTo enable auto-configuration for reactive Feign clients, add the
@EnableReactiveFeignClientsannotation to your Spring Boot configuration class. This will cause all interfaces annotated with@ReactiveFeignClientto be instantiated and configured as Spring beans.When defining a client:
- Use the
nameattribute in@ReactiveFeignClient. By default, the bean is registered asname + "ReactiveFeignClient"unless aqualifieris specified. - Cloud Mode: The
nameattribute is used as the Eureka application name. - Cloudless Mode: You must specify the
urlattribute.
@Configuration @EnableReactiveFeignClients public class MyFeignConfig { // Clients annotated with @ReactiveFeignClient will now be beans } @ReactiveFeignClient(name = "my-service") public interface MyServiceClient { // ... }- Use the
Add headers to reactive requests
developYou have two primary ways to add headers to your requests:
- ReactiveHttpRequestInterceptor: Use this for dynamic headers, such as extracting an authentication token from the Reactor
subscriberContext. - @RequestHeader parameter: Use the standard Feign
@RequestHeaderannotation on specific method parameters to pass a single header or a map of headers.
// Using an interceptor to add a static header and a dynamic header from context ReactiveFeignBuilder .addRequestInterceptor(ReactiveHttpRequestInterceptors.addHeader("Cache-Control", "no-cache")) .addRequestInterceptor(request -> Mono .subscriberContext() .map(ctx -> ctx .<String>getOrEmpty("authToken") .map(authToken -> { MultiValueMapUtils.addOrdered(request.headers(), "Authorization", authToken); return request; }) .orElse(request)));- ReactiveHttpRequestInterceptor: Use this for dynamic headers, such as extracting an authentication token from the Reactor
Use Cloud Mode (Hystrix + Ribbon)
developTo use the legacy Cloud mode (Hystrix + Ribbon), add the
feign-reactor-cloudmodule to your classpath.Global Toggle Properties (useful for testing):
reactive.feign.cloud.enabled: Disable cloud configuration for all clients.reactive.feign.ribbon.enabled: Disable loadbalancer configuration.reactive.feign.hystrix.enabled: Disable Hystrix configuration.reactive.feign.logger.enabled: Enable default logger.reactive.feign.metrics.enabled: Enable default Micrometer logger (requires a Micrometer implementation in your dependencies).
Specific Bean Customization:
- Ribbon: Define a
ReactiveLoadBalancer.FactoryorReactiveRetryPoliciesbean in your configuration. - Hystrix: Define a
CloudReactiveFeign.SetterFactorybean in your configuration.
Configure Reactive Feign via application.properties
developYou can configure specific settings for Feign clients using the prefix
reactive.feign.client.config.<client-name>.Available properties include:
options: Reactive HTTP client specific options (refer toReactiveOptions.Builderfor implementation details).retry: Retry configuration (seeReactiveFeignClientProperties.RetryConfiguration).statusHandler: Class implementingReactiveStatusHandler(replaces regular FeignErrorDecoder).errorMapper: Class implementingReactiveErrorMapper.requestInterceptors: Classes ofReactiveHttpRequestInterceptorfor setting up request headers.logger: Class ofReactiveLoggerListener.metricsLogger: Class ofMicrometerReactiveLogger.decode404: Boolean to handle 404 decoding (matches regular Feign behavior).
Configure Reactive Feign via Configuration Classes
developYou can provide configuration via Java classes using two levels of scope:
- Global Default: Use the
defaultConfigurationattribute on@EnableReactiveFeignClientsto specify a class used for all clients. - Client Specific: Use the
configurationattribute on@ReactiveFeignClientto specify a class for a single client.
The following bean types can be defined in your configuration classes:
ReactiveOptions.BuilderReactiveRetryPoliciesList<Class<ReactiveHttpRequestInterceptor>>ReactiveStatusHandlerfeign.codec.ErrorDecoderReactiveErrorMapperReactiveLoggerListenerMicrometerReactiveLogger
- Global Default: Use the