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 时,是否应该解码响应体。默认为 |
@FeignClient(name = "user-service", decode404 = true) |
loggerLevel |
设置 Feign 客户端的日志级别,可选值包括 |
@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
返回结果是有熔断类逻辑返回。