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.
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 compressionWhen 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: 30000If 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: 100000Feign 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
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
