[Spring Cloud] Declarative REST client: Feign

1. Introduction to Feign

Feign is a declarative HTTP client that simplifies the process of writing code for inter-service communication based on REST. In Spring Cloud, Feign plays an important role, it has pluggable annotation support, including Feign annotations and JAX-RS annotations. Feign Also supports pluggable 编码器 and 解码器. Spring CloudAdded support for Spring MVC annotations and uses the HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka or Nacos registries to provide load balancing when using Feign http client.

Feign feature introduction:

  • Declarative REST client:
    Feign allows developers to define calls to remote REST services using interfaces and annotations without having to worry about Low-level HTTP request and response handling. In Feign, various operations of remote services can be described through the definition of interface methods, including URL, request method, parameters and other information.
  • Integrated Load Balancing:
    By integrating the Ribbon load balancer, Feign Can automatically implement load balancing calls to specified services. This allows Feign to select the appropriate service instance to call based on the load balancing policy when the service provider has multiple instances.
  • Supports multiple request methods:
    Feign Supports various HTTP request methods, such asGET,, etc., thus making the call to remote services very flexible. , POST, PUTDELETE
  • Dynamic URL and parameter binding:
    Using Feign, parameters can be bound to the URL template , and pass dynamic data to the remote service. At the same time, Feign also supports binding parameters into the request body for POST or PUT requests.
  • Integrated Hystrix fault tolerance mechanism:
    Combined with the Hystrix circuit breaker in Spring Cloud, Feign can provide remote The fault tolerance of service calls includes timeout, circuit breaker and other functions, thereby enhancing the reliability of service calls.
  • Easy to integrate:
    In a Spring Cloud application, Feign integrates with other components such as, etc.) are seamlessly integrated and can be quickly enabled through simple dependency configuration and annotations, without the need for additional cumbersome configuration. Eureka, Zuul

In short, Spring Cloud Feign provides a concise and elegant way to define and call REST services. It simplifies the process of communication between services, improves development efficiency, and provides convenient support for building applications with a microservice architecture.

2. Basic use of Feign

Build a SpringCloud Demo, including producers and consumers. They are all ordinary web services, in which consumers have more dependencies on Feign than producers.

        <!-- SpringCloud Openfeign -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

And add annotations to the startup class:@EnableFeignClients
If fallbackFactorydowngrade is configured, you also need to introduce dependencies:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

Then add annotations to the startup class:@EnableHystrix, and add the configuration to enable service degradation:

feign:
  hystrix:
    enabled: true

2.1 Ordinary HTTP request

The producer provides an interface ofPOST:/student/queryList to query the data of the student table in the database.

@RestController
@RequestMapping("/student")
public class StudentController {
    
    

    @Resource
    private IStudentService studentService;

    @GetMapping("/queryList")
    public ApiR queryList(){
    
    
        List<Student> studentList = studentService.list();
        return ApiR.ok().data(studentList);
    }
}

The consumer uses Feign to remotely call the interface of this query list:

First create a new @FeignClient annotated interface

import com.lin.common.config.FeignSupportConfig;
import com.lin.common.constant.ServiceNameConstants;
import com.lin.common.vo.ApiR;
import com.lin.consumer.feign.fallback.RemoteStudentServiceFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;

/**
 * @author linmengmeng
 * @since 2023/11/12 14:12
 */
@FeignClient(contextId = "RemoteStudentService", name = ServiceNameConstants.PROVIDER_SERVICE
        , configuration = FeignSupportConfig.class, fallbackFactory = RemoteStudentServiceFallback.class)
public interface RemoteStudentService {
    
    

    @GetMapping ("/student/queryList")
    ApiR queryList();
}

I have registered both the producer and the consumer toNacos, so I can directly configure it herename = ServiceNameConstants.PROVIDER_SERVICE and call it directly through the producer's service name. the other party’s interface.

and configured a downgrade callback fallbackFactory = RemoteStudentServiceFallback.class, the downgrade operation implements the interface defined above and outputs specific exception information;

import com.lin.common.vo.ApiR;
import com.lin.consumer.feign.RemoteStudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.stereotype.Component;

/**
 * @author linmengmeng
 * @since 2023/11/12 14:22
 */
@Slf4j
@Component
public class RemoteStudentServiceFallback implements FallbackFactory<RemoteStudentService> {
    
    
    @Override
    public RemoteStudentService create(Throwable cause) {
    
    
        log.error("RemoteStudentServiceFallback error : {}", cause.getMessage());
        return () -> {
    
    
            log.error("sayHello error 接口调用异常");
            return ApiR.fail();
        };
    }
}

Add a test request interface and call the feign interface above:

import cn.hutool.json.JSONUtil;
import com.lin.common.vo.ApiR;
import com.lin.common.vo.R;
import com.lin.consumer.feign.RemoteStudentService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;

/**
 * 测试
 * @author linmengmeng
 * @since 2023/11/8 14:18
 */
@Slf4j
@RestController
@RequestMapping("/test")
public class TestController {
    
    

    @Resource
    private RemoteStudentService remoteStudentService;

    @GetMapping("/sayHello")
    public R sayHello() {
    
    
        log.info("sayHello。。。。。。");
        ApiR apiR = remoteStudentService.queryList();
        log.info("接口调用结果-apiR:{}", JSONUtil.toJsonStr(apiR));
        return R.ok();
    }
}

Start the consumer first, and then use Postman to call the consumer'ssayHello interface. You can see that Feign's remote interface is called in this interface. At this time, the producer has not started and the service The interfacequeryList will definitely be blocked. According to the original OkHTTP call, if the remote interface is abnormal, the exception will be passed to the interface caller. After the above configuration, let's call the interface and take a look:
Insert image description here
You can see that the interface responded normally, and then look at the consumer's log:

2023-11-12 22:18:11.504  INFO [io-37002-exec-1] [] c.l.consumer.controller.TestController   [29] : sayHello。。。。。。
2023-11-12 22:18:12.030  WARN [reakerFactory-1] [] o.s.c.l.core.RoundRobinLoadBalancer      [97] : No servers available for service: cloud-feign-provider
2023-11-12 22:18:12.033  WARN [reakerFactory-1] [] .s.c.o.l.FeignBlockingLoadBalancerClient [103] : Load balancer does not contain an instance for the service cloud-feign-provider
2023-11-12 22:18:12.065 ERROR [reakerFactory-1] [] c.l.c.f.f.RemoteStudentServiceFallback   [18] : RemoteStudentServiceFallback error : [503] during [POST] to [http://cloud-feign-provider/student/queryList] [RemoteStudentService#queryList()]: [Load balancer does not contain an instance for the service cloud-feign-provider]
2023-11-12 22:18:12.072 ERROR [reakerFactory-1] [] c.l.c.f.f.RemoteStudentServiceFallback   [20] : sayHello error 接口调用异常
2023-11-12 22:18:12.204  INFO [io-37002-exec-1] [] c.l.consumer.controller.TestController   [31] : 接口调用结果-apiR:{
    
    "code":500,"message":"系统繁忙,请稍后再试!","data":{
    
    "changeLog":"","detail":{
    
    },"releaseTime":"2023-11-12 22:18:12"}}

It can be seen that after the interface call is successful, when the Feign remote interface is called, two lines of Warn logs are printed, prompting us that the producer service is not found, and then the error log in our downgrade service is printed, and the interface we requested using postman Responded normally.

This is different from the OkHttp remote call interface we used before. Although the upstream service is abnormal here, it does not affect the call on our side. For consumers, it has its own closed-loop logic and will not pass the exception to itself. , the results and logs of the downgraded service can be obtained normally in our business logic.

Then start the producer's services respectively and call the consumer's interface again:

2023-11-12 22:31:50.722  INFO [io-37002-exec-2] [] c.l.consumer.controller.TestController   [29] : sayHello。。。。。。
2023-11-12 22:31:51.312  INFO [io-37002-exec-2] [] c.l.consumer.controller.TestController   [31] : 接口调用结果-apiR:{
    
    "code":200,"message":"成功","data":[{
    
    "id":"001","name":"Tom","age":19,"createTime":"2023-11-12T21:19:15"},{
    
    "id":"002","name":"Mary","age":18,"createTime":"2023-11-12T21:19:39"}]}

As you can see, the interface responded normally and the data was obtained.

2.2 Feign remote call upload file interface

Guess you like

Origin blog.csdn.net/linmengmeng_1314/article/details/134361613
Recommended