Degraded configuration of OpenFeign

Keywords: Java Spring Boot Spring Cloud RESTful

preface

When we need to call other microservices or third-party interfaces, we may use Dubbo or Spring's own component RestTemplate, but compared with the previous two, I prefer to use Feign, a component of Spring cloud. In my opinion, Feign is more flexible.

OpenFeign basic use

I'm too lazy to write a micro service myself. Here I searched a third-party interface on the Internet:
https://api.imjad.cn/cloudmusic/?type=song&id=32785674
Take this interface as an example

Dependencies required to use OpenFeign

<dependencies>
    <!-- SpringBoot Dependent configuration of-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-dependencies</artifactId>
        <version>2.5.0</version>
        <type>pom</type>
        <scope>import</scope>
    </dependency>
    <!--Remote interface call-->
    <!--openFeign-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <!-- SpringCloud Microservices -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2020.0.3</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

Here, the 2.5.0 SpringBoot version I use is 2020.0.3

Write Feign related logic

1. First, you need to add @ EnableFeignClients to the main method class

2. Write feign's interface

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

@FeignClient(url="https://api.imjad.cn", name = "music")
public interface RemoteMusicService {
    @GetMapping("/cloudmusic")
    public Object getMusic(@RequestParam("type") String type, @RequestParam("id") String id);
}


3. Write a controller to call RemoteMusicService

import com.swagger.demo.remoteAPI.RemoteMusicService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestOpenFeign {

    @Autowired
    private RemoteMusicService remoteMusicService;

    @GetMapping("/testFeign")
    public Object getMusic(String type, String id) {
        return remoteMusicService.getMusic(type, id);
    }

}

The test results after operation are as follows:

OpenFeign settings downgrade

When it comes to fusing and demotion, of course, the first thing we think of is Hystrix. Yes, we need it this time

1. Dependencies to add

<!--Fuse degraded use-->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
    <version>2.2.9.RELEASE</version>
</dependency>

2. Add support for Hystrix on the main method class

3. Add configuration in the application configuration file (enable Feign's support for Hystrix)

#feign.hystrix.enabled=true
feign.circuitbreaker.enabled=true

Note that my spring cloud version is 2020.0.3, and the configuration here is feign.circuitbreaker.enabled=true; If you are using a spring cloud version before 2020, the configuration information is feign.hystrix.enabled=true. (the problem with this version is still quite serious. I've planted it here before)

4. Set degradation for RemoteMusicService interface
There are two degradation methods here: fallback and fallbackFactory. Both can be degraded when the interface call fails. The latter can output more detailed information than the former. Next, let's all test it.

fallback mode:
First, write a fallback class and implement the corresponding degraded interface

import com.swagger.demo.remoteAPI.RemoteMusicService;
import org.springframework.stereotype.Component;

@Component
public class MusicFallback implements RemoteMusicService {
    @Override
    public Object getMusic(String type, String id) {
        System.out.println("Ha ha, ha ha, reported wrong");
        return "Ha ha ha";
    }
}

Don't forget to add @ Component here. When demoting, you need to get the bean object in the spring container
Add fallback configuration for RemoteMusicService:

Test output:

FallbackFactory mode:
First, write a FallbackFactory class and implement FallbackFactory < < corresponding degraded interface >

import com.swagger.demo.remoteAPI.RemoteMusicService;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;

@Component
public class MusicFallbackFactory implements FallbackFactory<RemoteMusicService> {
    @Override
    public RemoteMusicService create(Throwable cause) {
        // Similar to fallback, you need to return an object corresponding to the interface
        return new RemoteMusicService() {
            @Override
            public Object getMusic(String type, String id) {
                System.out.println("Ha ha, ha ha, reported wrong");
                return "Hahaha 123";
            }
        };
    }
}

Add MusicFallbackFactory configuration for RemoteMusicService:

Test output:

Posted by possiblyB9 on Mon, 20 Sep 2021 06:26:50 -0700