Understanding Feign: Working Principle, Annotations, GZIP, Logging, Timeout, and Parameter Handling

This article explains how Spring Cloud Feign works, details its key annotations, shows how to enable GZIP compression, configure logging and timeouts, and demonstrates techniques for handling multiple parameters in GET and POST requests with code examples.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Understanding Feign: Working Principle, Annotations, GZIP, Logging, Timeout, and Parameter Handling

Feign Working Principle

The main application class is annotated with @EnableFeignClients to enable scanning of @FeignClient interfaces. During startup, Spring scans for @FeignClient‑annotated interfaces, registers them in the IOC container, and creates JDK dynamic proxies that build a RequestTemplate for each method.

The RequestTemplate captures all HTTP request details (method, URL, parameters, etc.). It is then turned into a Request and handed to a Client implementation (e.g., JDK URLConnection, Apache HttpClient, or OkHttp). The client is wrapped by LoadBalanceClient, which integrates Ribbon for load‑balanced service calls.

Feign Annotation Analysis

The @FeignClient annotation is targeted at interfaces and provides several attributes: name: the service name used by Ribbon for discovery. url: optional fixed URL for debugging. decode404: if true, a 404 response is passed to the decoder instead of throwing an exception. configuration: custom configuration class to override encoder, decoder, log level, contract, etc. fallback: class implementing the interface to provide a fallback when the remote call fails. fallbackFactory: factory to create fallback instances, allowing shared fallback logic. path: common prefix for all requests of the client.

Feign GZIP Compression

Spring Cloud Feign can compress requests and responses with GZIP. Add the following configuration to application.yml:

feign:
  compression:
    request:
      enabled: true  # enable request compression
      mimeTypes: # 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, responses should be received as binary data using ResponseEntity<byte[]>.

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

Feign Client Logging

Define a configuration class to set the logger level:

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

Feign Timeout Settings

Feign calls involve two layers: Ribbon and (optionally) Hystrix. Configure Ribbon timeouts in application.yml:

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

If Hystrix is enabled, adjust its circuit‑breaker and execution settings:

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 Transmission

Feign does not fully support Spring MVC’s automatic POJO binding for GET requests. Work‑arounds include:

Declare each POJO field as a separate method parameter.

Pass parameters as a Map.

Use @RequestBody on a POJO (violates pure REST principles).

A request interceptor can convert a JSON body into query parameters for GET requests:

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

    @Override
    public void apply(RequestTemplate requestTemplate) {
        // Feign does not support GET with POJO body; convert JSON body to query string
        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 { // object node
            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 library 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>

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

Author & Source

Author: chendom

Original post: juejin.cn/post/6844903837543694349

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.

javaMicroservicesbackend-developmentConfigurationfeignSpring CloudHTTP client
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

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.