5
头图

background

Some time ago, a colleague encountered a problem and needed to use a custom URL in the Feign call of SpringCloud ; usually there is no such requirement; after all, SpringCloud is used, The calls between the services are all through the registry, and there is no need to customize the URL.

But there are also special ones. For example, we encounter the ToB scene here, and we need to call the customized URL for each merchant.

Although it is also possible to use the native Feign or even a custom one OKHTTP Client to achieve, but these schemes have to be written in a different way;

I plan to use the existing SpringCloud OpenFeign to implement, after all, the native Feign actually supports this function, and SpringCloud OpenFeign is only packaged on this basis. layer.

Just add a URI parameter to the interface declaration, so that you can pass different URI in each call to achieve the purpose of dynamic URL .


The idea is simple, but not so much in practice.
The pseudo code is as follows:

 @FeignClient(name = "dynamic")
    interface DynamicClient {
        @GetMapping("/")
        String get(URI uri);
    }
    
    dynamicClient.get(URI.create("https://github.com"));

After execution, a load balancing exception will be thrown:

 java.lang.RuntimeException: com.netflix.client.ClientException:
Load balancer does not have available server for client: github.com

This exception can also be understood, that is, the github service cannot be found; it is reasonable to find it, after all, it is not an internally registered service.

But according to the official introduction of Feign , as long as the interface declares URI this parameter can be customized, and I have also tested it with native Feign and there is no problem.

Debug

The problem can only be found in the package of SpringCloud OpenFeign ; after a colleague's search, I found a blog on the Internet to solve this problem.

https://www.cnblogs.com/syui-terra/p/14386188.html

According to the article, it is really only necessary to add the URL parameter and have a value, but the reason is unknown.

In the spirit of breaking the casserole to the end, I personally want to know how OpenFeign is handled, as long as the url has a value, it is completely a black box, and there is no such thing in the official comments. Circumstances have special instructions.

So I am ready to find the answer from the source code.

Since it can run normally if the url has a value, it must have obtained this value during the running process;


But I checked the place where the url is used in the source code, and I didn't find any application outside of the single test, indicating that the source code did not directly call url() this function to get the value.

But org.springframework.cloud.openfeign.FeignClient this annotation will always be used, so I checked the usage of this annotation.


Finally found traces of use here.

There are also some tricks when looking at the source code here. For example, if we query directly, IDEA's default query scope is the entire project and all dependent libraries, and there will be a lot of interference information.

For example, I only need to look at the source code of the project here, and I don't need to look at the single test; so I can filter it when I query, so that there will be much less interference information.

There are many filter conditions on the toolbar on the left, you can study it yourself.


Then read from the source code, you will find that all the data in @FeignClient eade8cab9fb9d323c63026be7bbc8e97--- is written to a Map for use.

Eventually you will find that this url is written to the url member variable in FeignClientFactoryBean .

See where this url is being used to see the rationale behind it.

A breakpoint here will find that: when the url is empty, it will return a LoadBalance of client , that is, a client that will get url from the registry , and url when there is a value, a default client will be obtained, so that load balancing will not be performed.

So if we want to use dynamic url in OpenFeign, we have to let @Feign's url have a value, no matter what it is.

Implementation of Feign

Now that I have seen this step, I am also curious how Feign uses the specified URL as long as there is a URI parameter?

Here is also a little trick for reading source code. If we follow the idea of program execution step by step debug , it will be very time-consuming. After all, the amount of code of such mature libraries is not small.

Here we can know from the official documentation that as long as it is used in the interface parameters java.net.URI will go to the custom url, so in turn, we only need to find where to use it in the source code java.net.URI You can know the key source code.

After all, there are not too many scenarios using java.net.URI .



So you only need to search in this dependent place cmd+shift+f global search java.net.URI to find the results, and there are not many, only two places are used.



In combination with the use scenario, the high probability is to judge whether there is a condition such as URL.class , or a url object; in short, we first use
URL Search for the keyword in these two files, remember to check the matching case; in the end, you will find that it is indeed judged whether there is URL this class, and at the same time this The index position is recorded.

Presumably, the final url information will be read through this index position in the future.

Finally, the core source code is queried through the use of this index. If there is a value, the address specified in the URI is taken as target .

So far, the rationale behind this problem has been analyzed.

Summarize

In fact, the focus of this article is to analyze some debug and some tips for reading source code, especially when reading about Spring related code, you must not debug and track the details, because the call chain is usually It is very long, and if you are not careful, you will be confused. You only need to know how to deal with the core and key source code.

Finally, there are indeed some doubts about OpenFeign's solution to handling dynamic urls. It is a typical scenario of 约定大于配置 , but the problem is that we don't know that this convention is @Feign the url must have value .

So I also mentioned one PR to OpenFeign , and interested friends can also check it out:

https://github.com/spring-cloud/spring-cloud-openfeign/pull/713


crossoverJie
5.4k 声望4k 粉丝