SpringCloud之OpenFeign简单使用
OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping
注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡
并调用
其他服务。
一、远程调用功能
- 创建提供服务的模块remote-feign-provider
- 引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
版本信息如下
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring-boot.version>2.4.2</spring-boot.version>
<spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
<nacos.version>2021.1</nacos.version>
<spring-cloud.version>2020.0.1</spring-cloud.version>
<spring-cloud-bootstrap.version>3.0.3</spring-cloud-bootstrap.version>
<spring-cloud-loadbalancer.version>3.0.1</spring-cloud-loadbalancer.version>
<spring-cloud-openfeign.version>3.0.1</spring-cloud-openfeign.version>
</properties>
- 创建主类
@EnableDiscoveryClient
@SpringBootApplication
public class RemoteFeignProviderApplication {
public static void main(String[] args) {
SpringApplication.run(RemoteFeignProviderApplication.class, args);
}
}
- 创建bootstrap.yml
spring:
application:
name: remote-feign-provider
cloud:
nacos:
discovery:
group: remote-group
namespace: remoteinvoke
server-addr: 192.168.56.102:8848
weight: 5
server:
port: 8082
注意nacos面板中需要新建相应的命名空间
- 创建TestController,提供相应的调用服务
@RestController
public class TestController {
@Value("${server.port}")
private int port;
@GetMapping("/service")
public String test(){
return "provicer servvice: [from port]:" + port;
}
}
开启8081,8082
两个端口的remote-feign-provider服务集群
- 下面开始创建调用模块,consumer模块
- 创建remote-feign-service模块
- 引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
- 主类
@SpringBootApplication
@EnableFeignClients(basePackages = "cn.axj.remote.feign.feign")
@EnableDiscoveryClient
public class FeignServiceApplication {
public static void main(String[] args) {
SpringApplication.run(FeignServiceApplication.class, args);
}
}
@EnableDiscoveryClient
默认要注册到注册中心,这个注解可加可不加。
@EnableFeignClients
: basePackages 用于OpenFeign扫描定义的FeignClient
包路径
- bootstrap.yml
spring:
application:
name: remote-feign-service
cloud:
nacos:
discovery:
group: remote-group
namespace: remoteinvoke
server-addr: 192.168.56.102:8848
weight: 5
server:
port: 8080
使用url形式的方式
- 创建LoadBalanceProviderOriginalFeignClient的接口,并利用SpringMvc的特性,将provider提供的服务/service声明成springmvc形式
@FeignClient(url = "http://localhost:8082",name = "remoteFeignSerivce")
public interface LoadBalanceProviderOriginalFeignClient {
@GetMapping("/service")
String service();
}
定义一个url为http://localhost:8082的服务ip/端口的服务,指定该类访问的基础ip地址和端口固定
关于@FeignClient注解,参数释义如下
参数名称 | 释义 | 示例 |
---|---|---|
name/value | 指定远程服务的名称,用于服务发现和调用。 | @FeignClient(name = "user-service") |
url | 直接指定远程服务的 URL 地址。当提供了 url 时,name 将被忽略。 | @FeignClient(url = "http://localhost:8080") |
configuration | 用于自定义 Feign 客户端的配置,可以包含自定义的 Encoder、Decoder、LoggerLevel 等。 | @FeignClient(name = "user-service", configuration = MyFeignConfiguration.class) |
fallback | 用于指定熔断降级类,当远程服务调用失败时,会调用这个降级类中的方法。 | @FeignClient(name = "user-service", fallback = UserServiceClientFallback.class) |
fallbackFactory | 用于创建熔断降级类的工厂,允许在创建降级类时注入其他依赖。 | @FeignClient(name = "user-service", fallbackFactory = UserServiceClientFallbackFactory.class) |
path | 定义所有请求的基础路径,会添加到每个请求的前面。 | @FeignClient(name = "user-service", path = "/api/v1") |
decode404 | 当服务器返回 404 时,是否应该解码响应体。默认为 false 。 | @FeignClient(name = "user-service", decode404 = true) |
loggerLevel | 设置 Feign 客户端的日志级别,可选值包括 NONE , BASIC , HEADERS , FULL 。 | @FeignClient(name = "user-service", loggerLevel = Logger.Level.FULL) |
primary | 当在 Spring 上下文中存在多个同名的 Feign 客户端时,标记哪个作为主要的 bean。 | @FeignClient(name = "user-service", primary = true) |
qualifier | 当需要区分多个同类型的 Feign 客户端时,用于指定一个唯一的名称,以便在注入时区分。 | @FeignClient(name = "user-service", qualifier = "myFeignClient") |
- 创建入口类Controller
@RestController
public class TestController {
@Resource
private LoadBalanceProviderOriginalFeignClient loadBalanceProviderOriginalFeignClient;
@GetMapping("/test")
public String test(){
return loadBalanceProviderOriginalFeignClient.service();
}
}
将FeignClient用组件的形式注入到Spring中,类似于Mybatis的Mapper类,OpenFeign会生产代理对象注入到Spring容器中
测试
启动remote-feign-service模块,访问localhost:8080/test,返回
provicer servvice: [from port]:8082
反复刷新,观察返回情况,可以看到返回信息一直是8082服务器返回的。
二、负载功能
OpenFeign默认开启负载,使用注册到注册中心的服务名称定义FeignClient。
- 在remote-feign-service模块中增加loadBalancer依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
- 创建负载类的LoadBalanceProviderFeignClient接口
@FeignClient(name = "remote-feign-provider")
public interface LoadBalanceProviderFeignClient {
@GetMapping("/service")
String service();
}
name
: 在注册中心中注册的调用服务名称
- 在TestController中注入该FeignClient
@RestController
public class TestController {
@Resource
private LoadBalanceProviderOriginalFeignClient loadBalanceProviderOriginalFeignClient;
@Resource
private LoadBalanceProviderFeignClient loadBalanceProviderFeignClient;
@GetMapping("/test")
public String test(){
return loadBalanceProviderOriginalFeignClient.service();
}
@GetMapping("/test2")
public String test2(){
return loadBalanceProviderFeignClient.service();
}
}
测试
重启remote-feign-service模块,访问localhost:8080/test2,观察返回
provicer servvice: [from port]:8082
provicer servvice: [from port]:8081
provicer servvice: [from port]:8082
provicer servvice: [from port]:8081
provicer servvice: [from port]:8082
....
此时已默认加入负载功能
三、熔断降级
当远程服务调用失败时,会采用熔断降级策略,调用熔断降级的方法返回。
熔断降级
需要搭配熔断降级组件使用,这里使用hystrix进行熔断
由于springcloud高版本openFeign已经默认移除了hystrix组件,这里需要手动加上hystrix依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
- bootstrap.yml中增加配置
feign:
circuitbreaker:
enabled: true
- 新建LoadBalanceProviderFeignClientFallback熔断类
@Component
public class LoadBalanceProviderFeignClientFallback implements LoadBalanceProviderFeignClient{
@Override
public String service() {
return "error fall back";
}
}
tips
: 必须将熔断类放入Spring容器中
- 配置FeignClient的熔断类,配置FeignClient
fallback
属性
@FeignClient(name = "remote-feign-provider",fallback = LoadBalanceProviderFeignClientFallback.class)
public interface LoadBalanceProviderFeignClient {
@GetMapping("/service")
String service();
}
重启remote-feign-service
模块,并将remote-feign-provider服务全部关掉。模拟熔断现象产生,访问localhost:8080/test2,观察返回
error fall back
返回结果是有熔断类逻辑返回