What is OpenFeign
Feign is a declarative Web service client that, in other words, lets you invoke a web service as easily as a method.
What can Feign do
Feign is designed to make writing Java Http clients easier.
Previously, when Ribbon+RestTemplate was used, the encapsulation of http requests using RestTemplate formed a set of templated invocation methods. However, in actual development, since there may be more than one call to a service dependency, an interface is often called from more than one place, so it is common to wrap calls to these dependent services by encapsulating some client classes for each microservice. So Feign further encapsulates this to help us define and implement the definition of dependent service interfaces. With the implementation of Feign, we can simply create an interface and configure it with annotations (previously labeled Mapper annotations on the Dao interface and now a Feign annotation on the microservice interface) to complete the interface binding to the service provider, simplifying the development of auto-encapsulating service invocation clients when using Spring cloud Ribbon.
Feign integrates Ribbon
Ribbon maintains Payment's service list information and balances the load on the client through polling. Unlike Ribbon, service calls are implemented elegantly and simply through feign by simply defining the service binding interface and using a declarative method
Differences between OpenFeign and Feign
Configuration steps
New Service Registry eureka
New module cloud-eureka-server 7001
Write the configuration file application.yml
server: port: 7001 eureka: instance: hostname: eureka7001.com #Instance name of eureka server side client: register-with-eureka: false #false means that you do not register yourself with the registry. fetch-registry: false #false says that my client is the registry and my responsibility is to maintain service instances without having to retrieve services service-url: #Clusters point to other eureka # defaultZone: http://eureka7002.com:7002/eureka/ #Single machine is 7001 itself defaultZone: http://eureka7001.com:7001/eureka/ #server: #Turn off self-protection to ensure unavailable services are kicked in time #enable-self-preservation: false #eviction-interval-timer-in-ms: 2000
Write Startup Class
@SpringBootApplication @EnableEurekaServer public class EurekaMain7001 { public static void main(String[] args) { SpringApplication.run(EurekaMain7001.class, args); } }
New Service Producer
New user module cloud-provider-payment8001
Increase service registration configuration eureka
eureka: client: #Indicates whether to register yourself in EurekaServer by default to true. register-with-eureka: true #Whether to grab existing registration information from EurekaServer or not, defaults to true. Single node doesn't matter, cluster must be set to true to use load balancing with ribbon fetchRegistry: true service-url: #Single machine version defaultZone: http://127.0.0.1:7001/eureka # Cluster Edition #defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka instance: instance-id: payment8001 #Access paths can display IP addresses prefer-ip-address: true #The time interval between Eureka clients sending heartbeats to the server in seconds (default is 30 seconds) #lease-renewal-interval-in-seconds: 1 #The maximum wait time for the Eureka server after receiving the last heartbeat in seconds (default is 90 seconds), and the timeout will exclude the service #lease-expiration-duration-in-seconds: 2
Startup Class Add @EnableEurekaClient, @EnableDiscoveryClient
//A startup class on the project that injects the startup class into the container, defines the scope of the container scan, and loads some bean s in the classpath environment. @SpringBootApplication /** * Register service with eruka */ @EnableEurekaClient @EnableDiscoveryClient public class PaymentMain8001 { public static void main(String[] args) { SpringApplication.run(PaymentMain8001.class, args); } }
New consumer module cloud-consumer-feign-order80
Write pom file
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>mscloud</artifactId> <groupId>com.zsy.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.zsy.springcloud</groupId> <artifactId>cloud-consumer-feign-order80</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <!--openfeign--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!--eureka client--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <!-- Introduce self-defined api Generic packages that can be used Payment payment Entity --> <dependency> <groupId>com.zsy.springcloud</groupId> <artifactId>cloud-api-commins</artifactId> <version>${project.version}</version> </dependency> <!--web--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!--General Basic Universal Configuration--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
Configure yml
server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/
Write the startup class (@EnableFeignClients)
package com.atguigu.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @auther zzyy * @create 2020-02-03 11:55 */ @SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class,args); } }
feign consumer remote service call interface
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); }
Write feign consumers
@RestController public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) { return paymentFeignService.getPaymentById(id); } }
test
- Start two eureka clusters 7001/7002 first
- Start another microservice 8001
- Start OpenFeign Start
- http://localhost/consumer/payment/get/1
- Feign built-in load balancing configuration item
feign timeout control
The feign default one-second timeout allows us to reproduce the timeout problem with the following configuration
Service producers write a service that takes three seconds
@GetMapping("/payment/timeoutCall") public String paymentFeignTimeOut(){ try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return "success"; }
Consumer configures this remote service
@Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") CommonResult<Payment> getPaymentById(@PathVariable("id") Long id); @GetMapping("/payment/timeoutCall") String paymentFeignTimeOut(); }
controller call code
@GetMapping("/consumer/payment/timeoutCall") public String paymentFeignTimeOut() { log.info("Try timeout remote call to determine if it will succeed"); return paymentFeignService.paymentFeignTimeOut(); }
Reproduce the timeout problem
yml adds the following configuration to solve the problem
#Set feign client timeout (OpenFeign supports ribbon by default) ribbon: #Refers to the time taken to establish a connection, and is applicable to the time taken to connect both ends under normal network conditions. ReadTimeout: 5000 #Refers to the time taken to read the available resources from the server after a connection has been established ConnectTimeout: 5000
feign adds print log functionality
feign also supports configuring to print out the entire process of a web service call
log level
NONE: By default, no logs are displayed; BASIC: Record only request methods, URL,Response status code and execution time; HEADERS: except BASIC In addition to the information defined in the, there is header information for requests and responses; FULL: except HEADERS In addition to the information defined in the, there is the body and metadata of the request and response.
Write Configuration Class
@Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } }
yml Add Configuration
logging: level: # At what level does the feign log monitor which interface com.zsy.springcloud.service.PaymentFeignService: debug