After the previous source code analysis, we are familiar with OpenFeign and the Ribbon.

The purpose of looking at the framework source code is to solve some of our doubts, to be able to know and know why, and use a good framework.

In many cases, we need to call some third-party interfaces in the project, such as alipay payment and wechat payment, and call the payment interface. If OpenFeign is introduced in the project, can we use OpenFeign to call third-party interfaces? The answer is definitely yes.

Although there is no service discovery required to invoke third-party interfaces, and therefore no need to use the Ribbon for load balancing, OpenFeign can still be used alone. Using OpenFeign not only simplifies the process of calling the interface, but also takes advantage of the retry mechanism provided by OpenFeign without the need to write an HttpUtils utility class.

The content of this article:

  • configurationOpenFeignuseOkHttp
  • OpenFeignRetry configuration of
  • OpenFeignInterceptor configuration

Configure OpenFeign to use OkHttp

OpenFeign sends HTTP requests through clients. The default Client uses HttpURLConnection to send HTTP requests.

If you don’t think HttpURLConnection performance is good, you can also use a custom Client to switch the action of sending HTTP requests to another framework that you think is better. OpenFeign also gives us a choice between using the OKHTTP framework and apache’s HttpClient framework.

When OpenFeign and the Ribbon work together, the OpenFeign Client actually sends the request to the service provider, so switching the Client is globally valid.

OpenFeign using okhttp framework for us to provide the Client the implementation of the interface (feign. Okhttp. OkHttpClient), And to provide automatic configuration class FeignAutoConfiguration OkHttpFeignConfiguration.

public class FeignAutoConfiguration {
    @Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(OkHttpClient.class)
	@ConditionalOnMissingClass("com.netflix.loadbalancer.ILoadBalancer")
	@ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
	@ConditionalOnProperty("feign.okhttp.enabled")
	protected static class OkHttpFeignConfiguration {
	    
	    @Bean
		@ConditionalOnMissingBean(Client.class)
		public Client feignClient(okhttp3.OkHttpClient client) {
			return newOkHttpClient(client); }}}Copy the code

This configuration class takes effect under the following conditions:

  • 1. Imported into the projectfeign-okhttpPackage, for the current projectclasspathThere is afeign.okhttp.OkHttpClientClass, which implementsClientInterface;
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>11.0</version>
</dependency>
Copy the code
  • 2, inapplication.yamlIn the configurationfeign.okhttp.enabledfortrue;
# configure feign to use okHTTP
feign:
  okhttp:
    enabled: true
Copy the code
  • 3. No importRibbonPackage, that is, not usedRibbonDoes not exist in the projectcom.netflix.loadbalancer.ILoadBalancerThis class;

When the Ribbon is used in a project, OpenFeign creates a LoadBalancerFeignClient instead of the Default Default and instead of OkHttpClient. FeignRibbonClientAutoConfiguration configuration class is set to complete the automatic configuration before FeignAutoConfiguration configuration class, Injected LoadBalancerFeignClient FeignRibbonClientAutoConfiguration the water in the container.

@AutoConfigureBefore(FeignAutoConfiguration.class)
@Import({ HttpClientFeignLoadBalancedConfiguration.class,
		OkHttpFeignLoadBalancedConfiguration.class,
		DefaultFeignLoadBalancedConfiguration.class })
public class FeignRibbonClientAutoConfiguration {
}
Copy the code

FeignRibbonClientAutoConfiguration using the @ Import Import three automatic configuration LoadBalancerFeignClient configuration class, but in the end will only have one to be imported, When we configure feign. Okhttp. Enabled to true, and the feign is added to the project – okhttp package dependency, OkHttpFeignLoadBalancedConfiguration effect.

@ConditionalOnProperty("feign.okhttp.enabled")
// Import the OkHttpFeignConfiguration automatic configuration class
@Import(OkHttpFeignConfiguration.class) 
class OkHttpFeignLoadBalancedConfiguration {
    @Bean
	@ConditionalOnMissingBean(Client.class)
	public Client feignClient(CachingSpringLoadBalancerFactory cachingFactory, SpringClientFactory clientFactory, // This okHttpClient is automatically configured by OkHttpFeignConfiguration for okHttp3. {
		OkHttpClient delegate = new OkHttpClient(okHttpClient);
		return newLoadBalancerFeignClient(delegate, cachingFactory, clientFactory); }}Copy the code

When OpenFeign is integrated with the Ribbon, OpenFeign uses a LoadBalancerFeignClient. However, the LoadBalancerFeignClient is only a bridge to achieve load balancing. Actual or through an authorized mode will send the request of the job to other Client, and is used here is feign. Okhttp. OkHttpClient.

Through the analysis of the source code in front of the study, we know that when configuring @ FeignClient annotation url attribute, not use LoadBalancerFeignClient, but we configure feign. Okhttp. OkHttpClient still take effect. Reason is OpenFeign won’t create a new Client, but will delegate object will be obtained from LoadBalancerFeignClient object feign. Okhttp. OkHttpClient.

We can also add a breakpoint debugging in FeignClientFactoryBean getTarget method, to verify using the @ FeignClient annotation comments third-party interface in the not to walk under the condition of service discovery, will use feign. Okhttp. OkHttpClient. Test omit…

When we call a third-party interface using OpenFeign, we need to give the URL of the interface directly on the @FeignClient annotation because the third-party interface does not go through service discovery. Since the @FeignClient annotation gives the url of the interface, OpenFeign never follows the load balancing logic, But from LoadBalancerFeignClient objects to the delegate object feign. Okhttp. OkHttpClient create the proxy object of the interface, so the final request is also used in the same call interface by feign. Okhttp. OkHttpClient.

Retry configuration for OpenFeign

OpenFeign for each Client to provide an environment isolated AnnotationConfigApplicationContext, in order to realize for different Client register configuration Bean, For example, Retryer and RequestInterceptor.

Each Client is not every interface annotated by the @FeignClient annotation, but a collection of interfaces annotated by the @FeignClient annotation with the same name, all pointing to the same service provider.

Instead of using OpenFeign’s retry mechanism, we might use the retry mechanism of the Ribbon. It is only necessary to use OpenFeign’s retry mechanism when using OpenFeign to call a third-party interface.

Complex implementations can inject configuration classes for each Client by getting the FeignContext. It is interesting to note that FeignContext is a NamedContextFactory, for each Client to provide a AnnotationConfigApplicationContext alone, And Ribbon SpringClientFactory is also a NamedContextFactory, also is for each Client to provide a AnnotationConfigApplicationContext alone.

When we annotate an interface with the @feignClient annotation, if we specify a Url that starts with HTTP, the Ribbon does not load balance. Based on this rule, we know exactly when the Ribbon retry mechanism is used. When can OpenFeign’s retry mechanism be used?

Since each Client is environment isolated, in addition to injecting configuration classes for each Client by getting FeignContext, the @FeignClient annotation’s Configuration property can also be used to import configuration classes.

Create a configuration class.

public class DefaultFeignRetryConfig {

    @Bean
    public Retryer retryer(a) {
        return new MyRetry();
    }

    private static class MyRetry implements Retryer {
        /** * Maximum number of retries */
        private final static int retryerMax = 1;
        /** * Current retry times */
        private int currentRetryCnt = 0;

        @Override
        public void continueOrPropagate(RetryableException e) {
            if (currentRetryCnt > retryerMax) {
                throw e;
            }
            // Try again if the connection is abnormal
            if (e.getCause() instanceof ConnectException) {
                currentRetryCnt++;
                return;
            }
            throw e;
        }

        @Override
        public Retryer clone(a) {
            return newMyRetry(); }}}Copy the code

Add the configuration class to the configuration property of the @FeignClient annotation.

@FeignClient(name = "alipay",
        path = "/v1",
        url = "${fegin-client.alipay-url}",
        configuration = {DefaultFeignRetryConfig.class})
Copy the code

OpenFeign interceptor configuration

OpenFeign provides request interceptors so that we can perform additional operations such as intercepting requests and adding Basic authorization information to the request header.

Just like configuring OpenFeign’s retries, configuring interceptors can inject multiple request Interceptors into the Client’s configuration class. Multiple request Interceptors must have the same name.

Call, for example, a company’s payment interface requires Basic authorization, so we need to register a BasicAuthRequestInterceptor add authorization head to all requests.

public class DefaultFeignRetryConfig {
    // Add authorization interceptor
    @Bean("basicAuthRequestInterceptor")
    public BasicAuthRequestInterceptor basicAuthRequestInterceptor(a) {
        return new BasicAuthRequestInterceptor("test"."test123456"); }}Copy the code

Finally, ensure that the configuration class has been added to the configuration property of the @FeignClient annotation.

@FeignClient(name = "alipay",
        path = "/v1",
        url = "${fegin-client.alipay-url}",
        configuration = {DefaultFeignRetryConfig.class})
Copy the code