Mastering Feign: How It Works, Configurations, and Advanced Usage

This article explains Feign’s internal workflow, details its key annotations, shows how to enable GZIP compression, configure logging, set timeouts, and handle multi‑parameter GET/POST requests, including custom request interceptors and dependency options for advanced Spring Cloud microservice communication.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
Mastering Feign: How It Works, Configurations, and Advanced Usage

Feign Working Principle

The main program entry adds the @EnableFeignClients annotation to enable scanning and loading of Feign clients. According to Feign client development conventions, an interface is defined and annotated with @FeignClient.

When the application starts, package scanning finds all classes annotated with @FeignClient and registers them in the Spring IoC container. When a method of a Feign interface is invoked, a JDK dynamic proxy creates a concrete RequestTemplate.

During proxy generation, Feign creates a RequestTemplate for each interface method, encapsulating all HTTP request information such as parameter names and HTTP method.

The RequestTemplate then builds a Request, which is handed to a Client for execution. The client can be JDK's URLConnection, Apache HttpClient, or OkHttp. Finally, the client is wrapped by LoadBalanceClient, which uses Ribbon for load‑balanced service calls.

Feign Annotation Analysis

The @FeignClient annotation is targeted at interfaces and provides several attributes:

name : specifies the Feign client name; when Ribbon is used, this name is the service identifier for discovery.

url : typically used for debugging, defines the address the client calls.

decode404 : if true, a 404 response is passed to the decoder instead of throwing a FeignException.

configuration : custom configuration class to override Feign's encoder, decoder, log level, contract, etc.

fallback : class that implements the Feign interface to provide a fallback when the remote call fails or times out.

fallbackFactory : factory that creates fallback instances, allowing shared fallback logic.

path : defines a common prefix for all requests of the client.

Feign GZIP Compression

Spring Cloud Feign supports GZIP compression for both requests and responses to improve communication efficiency.

feign:
  compression:
    request:
      enabled: true  # enable request compression
      mimeTypes: # media types, e.g., text/xml,application/xml,application/json
      minRequestSize: 2048  # minimum size to trigger compression
    response:
      enabled: true  # enable response compression

When compression is enabled, data must be transferred in binary form; therefore, responses should be received as ResponseEntity<byte[]>.

@FeignClient(name = "github-client", url = "https://api.github.com", configuration = HelloFeignServiceConfig.class)
public interface HelloFeignService {
    @RequestMapping(value = "/search/repositories", method = RequestMethod.GET)
    ResponseEntity<byte[]> searchRepositories(@RequestParam("q") String parameter);
}

Feign Client Logging

To enable logging, add a configuration class referenced by the @FeignClient annotation:

@Configuration
public class HelloFeignServiceConfig {
    /**
     * Logger.Level levels:
     * NONE – no logging
     * BASIC – log method, URL, status, and execution time
     * HEADERS – BASIC plus request/response headers
     * FULL – log everything including body and metadata
     */
    @Bean
    Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

Feign Timeout Settings

Feign calls involve two layers: Ribbon for load balancing and Hystrix for circuit breaking (Hystrix is disabled by default in newer versions).

Ribbon timeout error screenshot
Ribbon timeout error screenshot

If the above error occurs, configure Ribbon timeouts:

# Request processing timeout
ribbon.ReadTimeout: 12000
# Connection timeout
ribbon.ConnectionTimeout: 30000

When Hystrix is enabled, timeout errors appear as shown below:

Hystrix timeout error screenshot
Hystrix timeout error screenshot

Hystrix timeout settings can be added as follows:

hystrix:
  command:
    default:
      circuitBreaker:
        sleepWindowInMilliseconds: 30000
        requestVolumeThreshold: 50
      execution:
        timeout:
          enabled: true
      isolation:
        strategy: SEMAPHORE
        semaphore:
          maxConcurrentRequests: 50
        thread:
          timeoutInMilliseconds: 100000

Feign POST and GET Multi‑Parameter Passing

Spring MVC can bind request parameters to a POJO for POST/GET, but Feign does not fully support this. For GET requests, parameters cannot be bound to a POJO directly. Common work‑arounds include:

Write each POJO field as an individual method parameter.

Convert parameters into a Map.

Use @RequestBody on the POJO (violates RESTful principles).

The following interceptor converts a JSON body of a GET request into query parameters:

@Component
public class FeignRequestInterceptor implements RequestInterceptor {
    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void apply(RequestTemplate requestTemplate) {
        // feign does not support GET with POJO, convert JSON body to query
        if (requestTemplate.method().equalsIgnoreCase("GET") && requestTemplate.body() != null) {
            try {
                JsonNode jsonNode = objectMapper.readTree(requestTemplate.body());
                requestTemplate.body(null);
                Map<String, Collection<String>> queries = new HashMap<>();
                buildQuery(jsonNode, "", queries);
                requestTemplate.queries(queries);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void buildQuery(JsonNode jsonNode, String path, Map<String, Collection<String>> queries) {
        if (!jsonNode.isContainerNode()) { // leaf node
            if (jsonNode.isNull()) {
                return;
            }
            Collection<String> values = queries.get(path);
            if (values == null) {
                values = new ArrayList<>();
                queries.put(path, values);
            }
            values.add(jsonNode.asText());
            return;
        }
        if (jsonNode.isArray()) { // array node
            Iterator<JsonNode> it = jsonNode.elements();
            while (it.hasNext()) {
                buildQuery(it.next(), path, queries);
            }
        } else {
            Iterator<Map.Entry<String, JsonNode>> it = jsonNode.fields();
            while (it.hasNext()) {
                Map.Entry<String, JsonNode> entry = it.next();
                if (StringUtils.hasText(path)) {
                    buildQuery(entry.getValue(), path + "." + entry.getKey(), queries);
                } else { // root node
                    buildQuery(entry.getValue(), entry.getKey(), queries);
                }
            }
        }
    }
}

Alternatively, the venus-cloud-feign dependency provides built‑in support for GET parameter mapping:

<!-- https://mvnrepository.com/artifact/cn.springcloud.feign/venus-cloud-feign-core -->
<dependency>
    <groupId>cn.springcloud.feign</groupId>
    <artifactId>venus-cloud-feign-core</artifactId>
    <version>1.0.0</version>
</dependency>

The source code is available at:

https://github.com/SpringCloud/venus-cloud-feign.git
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Javaload balancingfeignSpring CloudHTTP client
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.