Two specific modes of operation for distributed remote calling SpringCloud-Feign (essence)

Time:2021-6-10

A preface

Introduction of several RPC frameworks

1. Support multi language RPC framework, Google’s grpc, Apache’s thrift
2. RPC framework only supports specific languages, such as Sina Motan
3. A distributed framework supporting service-oriented features such as service governance, such as Alibaba’s Dubbo
4. Spring with complete ecology   cloud
 

spring   Feign: the remote call mode of cloud

Feign is a declarative web service client, which makes it easier to write a web service client. Use fegin to create an interface and annotate it. It has pluggable annotation support, including feign annotation and jax-rs annotation. Feign also supports pluggable encoder and decoder. Spring cloud adds annotation to spring MVC. Spring Web uses httpmessage converters by default. Spring cloud integrates feign, a load balanced HTTP client provided by ribbon and Eureka.

Feign provides a template for HTTP request. By writing a simple interface and inserting comments, you can define the parameters, format, address and other information of HTTP request. Feign will completely proxy HTTP requests. We only need to call it like a method to complete service requests and related processing. Spring cloud encapsulates feign to support spring MVC standard annotations and httpmessage converters. Feign can be used in combination with Eureka and ribbon to support load balancing.

 

Official explanation:   Feign is a Java to HTTP client binder inspired by  RetrofitJAXRS-2.0, and WebSocket. Feign’s first goal was reducing the complexity of binding Denominator uniformly to HTTP APIs regardless of ReSTfulness.

 

Two ways to call feign

1 declare feign client directly in the caller

As shown in the figure below, service-b declares an interface to call the service of Service-A with the path of / user / get

 

2 declare feign client in API of callee interface

As shown in the figure below, declare the interface in the callee and call yourself. This method follows the interface oriented programming, and is similar to Dubbo in use. The @ autowire direct injection can be used

 

The above may make readers confused, the following specific code process, can facilitate a more specific understanding

 

The second case 1 is directly implemented in the feign client code declared by the caller

The following steps for hand-in-hand teaching, please understand my good intentions

Step 0 create a spring cloud Eureka registry

First, create a parent project

Delete everything else, leaving the POM file

 

The following are the dependencies of the parent project

4.0.0
    
    com.fegin
    test
    0.0.1-SNAPSHOT

    pom

    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.4.RELEASE
         
    


    
        1.8
        Greenwich.SR1
    

    
    
        
            
                org.springframework.cloud
                spring-cloud-dependencies
                ${spring-cloud.version}
                pom
                import

 

Create Eureka project

 

The project structure is shown in the figure

 

Add Eureka’s dependency

test
        com.fegin
        0.0.1-SNAPSHOT
    
    4.0.0

    eureka

    
    
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server

 

Add application.yml

server:
  port: 8761

eureka:
  instance:
    hostname: localhost
  client:
    #Do you register yourself as a service in another service registry
    registerWithEureka: false
    #Do you want to synchronize the service list from other service centers
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
  server:
    #Turn off the protection mechanism. True by default
    enable-self-preservation: false
    #Remove the service failure interval, the default is 60000
    eviction-interval-timer-in-ms: 3000

 

Add startup class code eurekaapplication

/**
 * @author c-can-z
 */
@EnableEurekaServer
@SpringBootApplication
public class EurekaApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }

}

 

Browser input http://localhost :8761/

 

Step 1 prepare a service ServiceA — the service is called

Create a common springboot service,   The service name is   service-a
In this service,   Create a port,   The port is: 9992
Access the path:
http://localhost:9991/user/get?id=5
Return to:   Congratulations on the 5th,   18-year-old Miss Meimei
 
 

Step 2   Prepare a service serviceb — the service is the caller

Create a serviceb

 

Add the necessary dependencies for serviceb

test
        com.fegin
        0.0.1-SNAPSHOT
    
    4.0.0

    serviceb

    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.projectlombok
            lombok
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

        
            org.springframework.cloud
            spring-cloud-starter-netflix-ribbon
        
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        

        
        
            org.springframework.cloud
            spring-cloud-starter-zipkin

 

Change application.properties to application.yml, the service name is service-b, and the port is 9992

server:
  port: 9992
spring:
  application:
    name: service-b
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
    Registry fetch interval seconds: 5. Refresh local cache time of Eureka client, 30 by default
  instance:
    prefer-ip-address: true
    #The time interval of Eureka client sending heartbeat to the server, in seconds (the client tells the server that it will follow this rule). The default is 30
    lease-renewal-interval-in-seconds: 5
    #The maximum waiting time of Eureka server after receiving the last heartbeat, in seconds. If it exceeds, it will be rejected (the client tells the server to wait for itself according to this rule). The default is 90
    lease-expiration-duration-in-seconds: 7
feign:
  client:
    config:
      default:
        connectTimeout: 7000
        readTimeout: 7000
service-b:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
logging:
  level:
    root: info

 

Import boot class file

@SpringBootApplication
@EnableFeignClients
public class SeriveBApplication {

    public static void main(String[] args) {
        SpringApplication.run(SeriveBApplication.class,args);
    }

}

 

Create feign client

//When creating this step, you need to pay attention to the description of step 1
//@Feignclient (name = "Service-A") annotation to bind the Service-A service corresponding to the interface
@FeignClient(name = "service-a")
public interface UserFeginClient {
    //The Service-A service corresponds to the resource path. You must add @ requestparam, otherwise an error will be reported, and the return parameter must also correspond to the resource path
    @RequestMapping("user/get")
    String get(@RequestParam("id")Long id);
}

 

Calling directly in the controller

@RestController
@RequestMapping("/product")
public class ProductController {

    @Autowired
    private UserFeginClient userFeginClient;

    @RequestMapping("/get")
    public String get(Long id){
        Return "product and service lottery" + userfegingclient. Get (ID) ";
    }
}

 

Step 3 test feign call effect

http://localhost:9992/product/get?id=5
 
Here is the simplest use of fegin
 
I believe that if you follow my steps step by step, you can understand what is:
Service-b declares an interface to call the service of Service-A with the path of / user / get
 

Three cases 2   Declare feign client code implementation in the callee interface API

Step 1: create the servicecapi, which is used to create feign client

It can be modified on the above projects
Project structure
 
Service API dependency
test
        com.fegin
        0.0.1-SNAPSHOT
    
    4.0.0

    servicec-api

    
        
        
            org.projectlombok
            lombok
        

        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign

 

Entity class product

public class Product implements Serializable {
    private Long id;
    private String name;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

 

Feign client

/**
 *Service name
 * @author c-can-z
 */
@FeignClient(name="service-c")
public interface ProductFeignApi {

    //The dynamic proxy needs an address, but we can't get it
    @RequestMapping("/servicec/get")
    Product get(@RequestParam("id") Long id);
}

 

Step 2 create serviceC service

Project structure

 

 

Service project dependency

test
        com.fegin
        0.0.1-SNAPSHOT
    
    4.0.0

    servicec
    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

        
        
            org.springframework.cloud
            spring-cloud-starter-zipkin
        

        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            com.fegin
            servicec-api
            0.0.1-SNAPSHOT

 

Application.yml of serviceC

server:
  port: 9993
spring:
  application:
    name: service-c
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
    Registry fetch interval seconds: 5. Refresh local cache time of Eureka client, 30 by default
  instance:
    prefer-ip-address: true
    #The time interval of Eureka client sending heartbeat to the server, in seconds (the client tells the server that it will follow this rule). The default is 30
    lease-renewal-interval-in-seconds: 5
    #The maximum waiting time of Eureka server after receiving the last heartbeat, in seconds. If it exceeds, it will be rejected (the client tells the server to wait for itself according to this rule). The default is 90
    lease-expiration-duration-in-seconds: 7
feign:
  client:
    config:
      default:
        connectTimeout: 7000
        readTimeout: 7000
logging:
  level:
    root: info

 

The implementation of feign client interface is also the core code of this article

The method of implementation is adopted

/**
 *Implementation class of remote call interface
 * @author c-can-z
 */
@RestController
public class ProductFeignClient implements ProductFeignApi {

    @Override
    public Product get(Long id) {
        Product product = new Product();
        product.setId(id);
        Product. Setname ("I am Service C");
        return product;
    }
}

 

Start class of serviceC

@SpringBootApplication
public class ProductServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProductServerApplication.class, args);
    }
}

 

Step 3 create a serviced service to call serviceC

Project structure

Note the location of the startup class. The path of servicecapi must be scanned by the startup class

 

Service dependency,

Note that the API of serviceC must be introduced. Some people will say that there is a problem of code intrusion. However, compared with case 1, if multiple projects are called and multiple feign clients are created, which is right or wrong depends on the specific requirements of the project

test
        com.fegin
        0.0.1-SNAPSHOT
    
    4.0.0

    serviced

    
        
        
            org.springframework.boot
            spring-boot-starter-web
        
        
        
            org.springframework.boot
            spring-boot-starter-test
            test
        
        
        
            org.projectlombok
            lombok
        
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        
        
        
            org.springframework.cloud
            spring-cloud-starter-openfeign
        
        
        
            org.springframework.cloud
            spring-cloud-starter-zipkin
        

        
            com.fegin
            servicec-api
            0.0.1-SNAPSHOT

 

Application.yml of serviced

server:
  port: 9994
spring:
  application:
    name: service-d
  zipkin:
    base-url: http://localhost:9411
  sleuth:
    sampler:
      probability: 1
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8761/eureka/
    Registry fetch interval seconds: 5. Refresh local cache time of Eureka client, 30 by default
  instance:
    prefer-ip-address: true
    #The time interval of Eureka client sending heartbeat to the server, in seconds (the client tells the server that it will follow this rule). The default is 30
    lease-renewal-interval-in-seconds: 5
    #The maximum waiting time of Eureka server after receiving the last heartbeat, in seconds. If it exceeds, it will be rejected (the client tells the server to wait for itself according to this rule). The default is 90
    lease-expiration-duration-in-seconds: 7
feign:
  client:
    config:
      default:
        connectTimeout: 7000
        readTimeout: 7000
logging:
  level:
    root: info

 

Control class of service

/**
 * @author c-can-z
 */
@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private ProductFeignApi productFeignApi;

    @RequestMapping("/get")
    public String get(Long id){
        Product product = productFeignApi.get(id);
        Return "order is: Product: + product. Getname() +", product ID: + product. Getid();
    }
}

 

Start class of service

/**
 * @author c-can-z
 */
@SpringBootApplication
@EnableFeignClients
public class ServiceDApplication {
    public static void main(String[] args) {
        SpringApplication.run(ServiceDApplication.class,args);
    }
}

 

Step 4 test feign call effect

http://localhost:9994/order/get?id=5

 

IV. summary

Here, I don’t know if you understand   Declare feign client or   Declare feign client in the callee interface API

Declare feign client directly in the caller:

Every service needs to create a client to call other services, which is relatively troublesome in terms of code

Declare feign client in the callee interface API:

From the point of view of the caller, it is as convenient to use as the Dubbo of Taobao, but every service calls other services, it needs to introduce the API dependency of other services. From the point of view of the interdependence between projects, it will be relatively troublesome