table of Contents
1 Introduction
Feign
Is a declarative web service
client, it makes it easier to write a web service client. Create an interface, add annotations to the interface, and then you can use Feign. Feign can use Feign annotations or JAX-RS annotations, and also supports hot-swappable encoders and decoders.
Spring Cloud adds Spring MVC annotation support to Feign, and integrates Ribbon
and Eureka
to provide load balancing when using Feign. Use @EnableFeignClients
to turn on Feign.
in short:
Feign采用的是基于接口的注解
Feign默认整合了ribbon,具有负载均衡的能力
Feign默认整合了Hystrix,具有熔断的能力
OpenFeign attribute configuration list document : https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.2.RELEASE/reference/html/appendix.html
OpenFeign official tutorial document : https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.2.RELEASE/reference/html/#configuration-properties
2. Exploring Feign
The communication between microservices is based on HTTP, and Feign is a pseudo HTTP request client. Through the declarative Feign client, remote microservices can be called. In the process of implementing remote microservice calls, when multiple instances exist, The Ribbon load balancer will perform local load balancing by default, by default by 轮询机制
making microservice calls, and Feign is integrated and supports Ribbon load balancing by default.
Take order service ( Order
) to call commodity service ( Product
) as an example, set up an environment to use Feign to call consumer services remotely.
3. Product engineering
pom.xml
<?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>springcloud-alibaba-nacos</artifactId>
<groupId>com.bruce.springcloud-alibaba-nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-alibaba-provider</artifactId>
<dependencies>
<!-- web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除tomcat依赖 -->
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--undertow容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!--nacos服务注册与发现 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8715
spring:
cloud:
nacos:
discovery:
#服务注册与发现地址
server-addr: 127.0.0.1:8848
#开启服务注册与发现功能
enabled: true
application:
name: nacos-product
Commodity service interface ProviderController
@Slf4j
@RestController
public class ProductController {
@Value("${server.port}")
private String port;
@GetMapping(value = "/getProductInfo/{productId}")
public String getProductInfo(@PathVariable("productId") String productId) {
log.info("请求进来啦");
return "Hello Nacos Discovery " + productId;
}
}
Start class ProductProviderApp
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @BelongsProject: springcloud-alibaba-nacos
* @BelongsPackage: com.bruce
* @CreateTime: 2021-02-18 13:08
* @Description: TODO
*/
@SpringBootApplication
public class AppProvider {
public static void main(String[] args) {
SpringApplication.run(AppProvider.class);
}
}
4. Order project
pom.xml
<?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>springcloud-alibaba-nacos</artifactId>
<groupId>com.bruce.springcloud-alibaba-nacos</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>springcloud-alibaba-consumer</artifactId>
<dependencies>
<!-- Alibaba-nacos服务发现-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<artifactId>nacos-client</artifactId>
<groupId>com.alibaba.nacos</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- nacos-client -->
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>1.2.0</version>
</dependency>
<!-- hystrix断路器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
<!-- openfeign客户端 ,默认集成并开启了ribbon负载均衡-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<!--排除tomcat依赖 -->
<exclusion>
<artifactId>spring-boot-starter-tomcat</artifactId>
<groupId>org.springframework.boot</groupId>
</exclusion>
</exclusions>
</dependency>
<!--undertow容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>6</source>
<target>6</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
application.yml
server:
port: 8710
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
enabled: true
application:
name: nacos-order
Define Feign client OrderFeign
The Hystrix fuse component is introduced in OrderFeign to protect and degrade the service. There are two ways to use circuit breaker support in the @FeignClient annotation: fallback and fallbackFactory
About Feign Hystrix Fallbacks:
The first: Hystrix supports the concept of fallback: when their circuit is broken or an error occurs, the default code path will be executed. To enable fallback for a given @FeignClient set, the fallback attribute should be the name of the class that implements the fallback. You also need to declare the implementation as a Spring bean.
import com.thinkingcao.order.feign.callback.OrderFeignFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "nacos-product",fallback = HystrixClientFallback.class)
public interface OrderFeign {
@GetMapping(value = "/getProductInfo/{productId}")
public String getProductInfo(@PathVariable("productId") String productId);
@Component
@Slf4j
static class HystrixClientFallback implements OrderFeign {
@Override
public String getProductInfo(String productId) {
return "fallback; reason was: 服务忙,稍后重试" ;
}
}
}
The second type : If you need to access the cause of the fallback trigger, you can use the attribute @FeignClient of fallbackFactory inside. To put it bluntly, if you want to know why the service call failed, you can use the following circuit breaker method.
import com.thinkingcao.order.feign.callback.OrderFeignFallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(name = "nacos-product",fallbackFactory = OrderFeignFallbackFactory.class)
public interface OrderFeign {
@GetMapping(value = "/getProductInfo/{productId}")
public String getProductInfo(@PathVariable("productId") String productId);
@Component
@Slf4j
static class OrderFeignFallbackFactory implements FallbackFactory<OrderFeign> {
@Override
public OrderFeign create(Throwable throwable) {
log.error("调用异常:"+ throwable.toString());
return new OrderFeign() {
@Override
public String getProductInfo(String string) {
return "开启断路-fallback; reason was: "+ throwable;
}
};
}
}
Service consumption OrderController
package com.bruce.controller;
import com.bruce.client.OrderFeign;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
/**
* @BelongsProject: springcloud-alibaba-nacos
* @BelongsPackage: com.bruce.controller
* @CreateTime: 2021-02-18 15:19
* @Description: TODO
*/
@RestController
@Slf4j
public class OrderController {
@Autowired
private OrderFeign orderFeign;
@GetMapping("/getProduct/{productId}")
public String getProduct(@PathVariable("productId") String id){
String response = orderFeign.getProductInfo(id);
log.info("调用服务结束: "+ response);
return response;
}
}
Start class OrderConsumerApp
1. @SpringCloudApplication : Combined annotation:
@SpringBootApplication(启动SPringBoot程序)、
@EnableDiscoveryClient(开启服务注册与发现)、
@EnableCircuitBreaker(开启断路器)
2. @EnableFeignClients : Enable Feign clients
package com.bruce;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/**
* @BelongsProject: springcloud-alibaba-nacos
* @BelongsPackage: com.bruce
* @CreateTime: 2021-02-18 13:16
* @Description: TODO
*/
//@SpringBootApplication
@SpringCloudApplication
@EnableFeignClients
public class AppConsumer {
public static void main(String[] args) {
SpringApplication.run(AppConsumer.class);
}
}
5. Test
Address: http://127.0.0.1:8710/getProduct/10