Feign 简介
Spring Cloud Feign 是一个 HTTP 请求调用的轻量级框架,可以以 Java 接口注解的方式调用 HTTP 请求,而不用通过封装 HTTP 请求报文的方式直接调用
Feign 通过处理注解,将请求模板化,当实际调用的时候传入参数,根据参数再应用到请求上,进而转化成真正的请求
第一个 Feign 程序
本小节介绍如何通过 Nacos+Feign 实现服务之间的调用,新建 server-01、server-02 项目,并分别注册 Nacos
server-01 引入依赖
org.springframework.cloud spring-cloud-starter-openfeign org.springframework.cloud spring-cloud-starter-loadbalancer
新建 Server02FeignClient 接口,用于调用 server-02 提供的对外接口
// name:要调用的服务名FeignClient(name = "server-02")public interface Server02FeignClient { @GetMapping("/test/getConfig") void getConfig();}
启动类加上注解 @EnableFeignClients
@EnableFeignClients@EnableDiscoveryClient@SpringBootApplicationpublic class Server01Application { public static void main(String[] args) { SpringApplication.run(Server01Application.class, args); }}
使用 Server02FeignClient 调用 server-02 的接口
@Slf4j@RestControllerpublic class TestCon { @Autowired private Server02FeignClient server02FeignClient; @GetMapping("/test/getConfigByFeign") public void getConfigByFeign() { server02FeignClient.getConfig(); }}
在 server-02 创建接口
@Slf4j@RestControllerpublic class TestCon { @Value("${test.value}") private String testValue; @Value("${spring.application.name}") private String applicationName; @Value("${server.port}") private String port; @GetMapping("/test/getConfig") public void getConfig() { log.info("testValue: {} by {}-{}", testValue, applicationName, port); }}
调用 server-01 的 /test/getConfigByFeign
接口,就会通过 Feign 调用 server-02 的 /test/getConfig
接口
@FeignClient
注解可作用在类、接口、枚举上,主要包含如下属性:
name/value:name 是 vaue 的别名,value 也是 name 的别名,两者的作用是一致的,用指定 FeignClient 的名称,如果配合注册中心使用,则作为微服务的名称,用于服务发现
url:主要用于调试,可以手动指定
@FeignClient
调用的地址path:path 用于定义当前 FeignClient 的统一前缀
contextld:如果要创建多个具有相同名称或 URL 的 Feign 客户端,以便它们指向同一台服务器,但是每个客户端具有不同的自定义配置,则必须使用 contextId 属性,以避免这些配置的名称冲突
@FeignClient(contextId = "fooClient", name = "stores", configuration=FooConfiguration.class)public interface FooClient {...}@FeignClient(contextId = "barClient", name = "stores", configuration=BarConfiguration.class)public interface BarClient {...}
fallback/fallbackFactory:
fallback:定义容错的处理类,当调用远程接口失败或超时时,就会调用对应接口的容错逻辑,falback 指定的类必须实现
@FeignClient
标记的接口fallbackFactory:工厂类,用于生成 fallback 类,通过该属性可以实现每个接口通用的容错逻辑,减少重复的代码
decode404:当发生 404 错误时,如果该字段为 true,就会调用 decoder 进行解码,否则抛出异常
Configuration:Feign 配置类可以自定义 Feign 的 Encoder、Decoder、LogLevel、Contract 等,OpenFeign 默认为 Feign 提供以下对象(bean 类型 bean 名称 : 类名称):
Decoder feignDecoder : ResponseEntityDecoder
Encoder feignEncoder : SpringEncoder
Logger feignLogger : Slf4jLogger
Contract feignContract : SpringMvcContract
FeignBuilder feignBuilder : HystrixFeignBuilder
spring-cloud-starter-openfeign 支持 spring-cloud-starter-netflix-ribbon 和 spring-cloud-starter.loadbalancer,如果 Ribbon 在类路径中且已启用,则 Client feignClient 是 LoadBalancerFeignClient,如果 SpringCloud LoadBalancer 在类路径中,则使用 FeignBlockingLoadBalancerClient
默认情况下,Spring Cloud OpenFeign 不会为 Feign 提供以下 bean 对象,但是仍然会从应用程序上下文中查找这些类型的 bean 以创建 Feign 客户端:
- Logger.Level
- Retryer
- ErrorDecoder
- Request.Options
- Collection
- SetterFactory
- QueryMapEncoder
以上是通过注解 @FeignClient
的配置属性进行配置的,我们也可以使用配置文件进行配置
feign: client: config: feignName: connectTimeout: 5000 readTimeout:5000 loggerLevel: full errorDecoder: com.example.SimpleErrorDecoder retryer: com.example,SimpleRetryer requestInterceptors: - com.example.FooRequestInterceptor - com.example,BarRequestInterceptor decode404: false encoder: com.example.SimpleEncoder decoder: com.example.SimpleDecoder contract: com.example.SimpleContract
可以在 @EnableFeignClients
属性 defaultConfiguration 中指定默认配置,不同之处在于此配置将适用于所有 Feign 客户端
如果希望使用配置文件来配置所有 @FeignClient
,则可以使用默认 Feign 名称创建配置属性,例如:
feign: client: config: default: connectTimeout: 5000 readTimeout: 5000 loggerLevel: basic
如果同时创建 @Configuration
bean 和配置文件,则配置文件将覆盖 @Configuration
值,如果要将优先级更改为 @Configuration
,就可以将 feign.client.default-to-properties
更改为 false
Feign 传参
以下服务端接口可通过 Get 或 Post 请求调用并接收参数
@RequestMapping("/test/testFeignWithParam")public void testFeignWithParam(@RequestParam String name, @RequestParam int age) { log.info("testFeignWithParam: name-{}, age-{}", name, age);}
通过在 Url 拼接请求传参如下:
@FeignClient(name = "server-02", path = "server-02")public interface Server02FeignClient { @GetMapping("/test/testFeignWithParam?name=zhanghsan&age=66") //@PostMapping("/test/testFeignWithParam?name=zhanghsan&age=66") void testFeignWithParam();}
使用 @RequestParam
传参如下:
@FeignClient(name = "server-02", path = "server-02")public interface Server02FeignClient { //@GetMapping("/test/testFeignWithParam") @PostMapping("/test/testFeignWithParam") void testFeignWithParam(@RequestParam("name") String name, @RequestParam("age") int age);}
也可以使用 OpenFeign 的 @QueryMap
将请求实体作为参数的映射,不过由于 @QueryMap
注解与 Spring 不兼容,所以 OpenFeign 提供了等效的 @SpringQueryMap
注解
@FeignClient(name = "server-02", path = "server-02")public interface Server02FeignClient { //@GetMapping("/test/testFeignWithQueryMap") @PostMapping("/test/testFeignWithQueryMap") void testFeignWithQueryMap(@SpringQueryMap FeignParam param);}