1. Introduce 😄

This article mainly introduces some additional properties of Feign-core. For details on how feign-Core works, and how it is integrated with Spring-Boot, see the previous two articles.

Focus of this paper:

1) How does Feign-core implement the selection among multiple services (i.e. how the load balancing strategy is implemented)?

2) How to gracefully transfer header information in HTTP requests with method-level calls between services?

2. Load balancing

2.1 Where to Start

When I opened the feign-Core source code, I came across a ribbon directory, 😄. I guessed that the ribbon must be inherited by maven.

Feign – Core Ribbon inherited directory

Feign-core Maven relies on ribbon

2.2 the debug start

This step requires project support. Please refer to github- source code and start eurake, Provider, and CONSUMner successively.

Before debug, what is our purpose?

1) Find out where the remote call is made;

According to the previous two articles: feign – basic use, feign – core and core spring – the boot integration, we get SynchronousMethodHandler. Invoke () is the place that ultimately perform remote calls; Debug directly from here, as for the generation of proxy objects is not the focus of this article;

  1. Trace debug to find calls to ribbon related classes.

After debugging, the following sequence diagram is obtained:

2.3 Summary conclusions 😎

Before summarizing the results, let’s look at the sequence diagram of spring-Boot and Ribbon integration (in RestTemplate form).


  1. The comparison shows that the entry points of the ribbon, Spring-boot and Feign-core are all on the Client.

  2. Client is the interface for clients to initiate requests. The ribbon encapsulates load balancing and HTTP calls.

  3. The ribbon replaces ${application-server-name] in the Request object with an actual host address, and applies load balancing policies 😄.

3. Service interception 🚀

3.1 the status quo

Springmvc we can use the Filter, HandlerInterceptor to intercept enhanced request, fein-core HTTP call similar to dubbo RMI request, so how to implement enhanced request?

First, start the project (see the project in 2.2). Let’s see if the header value is normally carried after the feign-core request.

Access path curl:

curl --location --request GET 'localhost:18084/eat/apple' \
--header 'user-token: 12138' \
--header 'yiyi-podenv: edu-12138'
Copy the code

Debug Provider result:

As you can see, the feign-core call does not carry the value of the header by default;

3.2 transform 🔧

As a tool for 🐂🍺, Feign-Core also provides ways to enhance services; RequestInterceptor interface;

Before transformation, we first simulated a demand:

  1. Feign-core requests to reserve the user’s request IP;

  2. Feign-core requests headers with custom headers (tentative prefix: yiyi)

Add the following configuration classes on the Consumer side

HttpHeaderConstant

/** * HTTP header requests constant */
public interface HttpHeaderConstant {

    String X_FORWARDED_FOR = "x-forwarded-for";

    String ENV_PREFIX = "yiyi";

}
Copy the code

FeignHeaderIntercept

@Configuration
public class FeignHeaderIntercept implements RequestInterceptor {

    private Logger logger = LoggerFactory.getLogger(FeignHeaderIntercept.class);

    @Override
    public void apply(RequestTemplate template) {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        if(Objects.isNull(requestAttributes)){
            return;
        }

        HttpServletRequest request = requestAttributes.getRequest();
        Enumeration<String> headerNames = request.getHeaderNames();

        if(Objects.isNull(headerNames)){
            return ;
        }

        boolean xForwardIpExist = false;
        while (headerNames.hasMoreElements()){
            String name = headerNames.nextElement();
            String values = request.getHeader(name);

            // Obtain the real IP address of the user
            if (name.equalsIgnoreCase(HttpHeaderConstant.X_FORWARDED_FOR)) {
                if(IpUtils.isLocalAddress(values)){
                    values = IpUtils.getIpAddr(request);
                }
                template.header(HttpHeaderConstant.X_FORWARDED_FOR,values);

                xForwardIpExist = true;
            }

            // Customize HTTP header retrieval
            if(name.startsWith(HttpHeaderConstant.ENV_PREFIX)){
                values = request.getHeader(name);
                logger.info("HTTP interception header: name = {},values = {}",name,values); template.header(name,values); }}if(! xForwardIpExist){ String remoteAddr = IpUtils.getIpAddr(request); logger.info(Httpx-forwarded-for Adds remoteAddr header: {},remoteAddr); template.header(HttpHeaderConstant.X_FORWARDED_FOR,remoteAddr); }}}Copy the code

Debug View result

Ok, that works

3.3 pay attention to

FeignHeaderIntercept configuration class, it is recommended to encapsulate into a public base package, convenient global unified processing;

See 📚

Feign-core is basically used

Feign-core integration with Spring-boot

Load Balancing – Ribbon