说明
通过之前的几篇博文,我简单介绍了OpenFeign的使用及其工作原理。OpenFeign的易用性和扩展性让人印象深刻。接下来,我将继续学习Spring是如何对OpenFeign进行集成支持,使其在Spring Cloud 微服务体系中发挥着重要的作用。在本篇博文中,我将结合官方文档介绍Spring Cloud OpenFeign,了解其基本使用方式及功能特性。
进行服务间的调用无外乎HTTP请求或者RPC调用,在Spring Cloud 微服务体系中也支持了这两种方式。分别是以HTTP请求为基础的Spring Cloud OpenFeign 和阿里的dubbo。Spring Cloud OpenFeign 则是以OpenFign为基础,通过自动装配将其集成到Spring Boot应用中,纳入到Spring体系中。
通过官方文档我们可以初步了解Spring Cloud对OpenFeign做了那些改造支持。
可以看到Spring Cloud添加了对Spring MVC注解的支持和Spring Web使用的HttpMessageConverters, 并且集成了Ribbon 和 Eureka,提供了可以进行负载均衡了Http Client。
接下来,通过简单项目介绍如何使用Spring Cloud OpenFeign。
正文
快速上手
首先引入Spring Cloud OpenFeign 依赖,同时因为基于Eureka的服务注册发现,还要引入Eureka-Client 依赖。基于Spring Boot 2.1.14版本:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
引入后,在项目启动类分别加上@EnableDiscoveryClient和@EnableFeignClients注解:
@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class Feign2ClientApplication {
public static void main(String[] args) {
SpringApplication.run(Feign2ClientApplication.class, args);
}
}
在application.yml中配置项目名称,端口和注册中心Eureka地址:
spring:
application:
name: feign2-client
server:
port: 2003
eureka:
client:
service-url:
defaultZone: http://localhost:1001/eureka/
创建服务接口,使用@FeignClient注解:
@FeignClient(value = "feign2")
public interface Feign2Service {
}
至此,OpenFeign的服务已经配置完毕,通过@Autowired自动注入进行服务调用。
@Autowired
private Feign2Service feign2Service;
可以看到与之前OpenFeign的使用方式相比,我们不再需要使用其他注解配置,不用进行手动创建Feign Client 直接使用SpringMVC的注解, @FeignClient注解即可。同时,Spring Cloud OpenFeign 也支持了手动创建Feign Client,这种方式与OpenFeign相似,这里不再赘述,更多请看官方文档。
在@FeignClient注解的value值表示client名称,该名称被用来创建Ribbon load-balancer或者 Spring Cloud LoadBalancer 。负载均衡器通过该名称进行服务端物理地址的获取,如果项目是eureka-client,则通过eureka注册中心进行服务地址解析。
同时,如果项目没有使用eureka注册中心,@FeignClient注解也支持通过配置url参数来指定服务端的url。同时,文档提到也可以使用SimpleDiscoveryClient,并配置服务地址列表。
没有eureka注册中心,通过url指定服务地址:
@FeignClient(value = "feign2", url = "http://localhost:2003")
public interface Feign2Service {
}
文档提到,为了保持向后兼容性,Rabbion作为默认的负载均衡器实现。但是由于Spring Cloud Netfix Ribbon项目已经进入维护状态,官方建议使用Spring Cloud LoadBalancer进行替代。可以设置spring.cloud.loadbalancer.ribbon.enabled 值为false进行配置。
自定义配置
先通过文件上传示例代码来了解如何修改Spring Cloud OpenFeign的默认配置:
在OpenFeign的feign-form项目中,我们了解了如何实现表单提交,主要是配置Encoder。在Spring中,我们需要配置SpringFormEncoder。
这里不需要引入额外的依赖,在spring-cloud-starter-openfeign依赖中,已经引入了feign-java8依赖,该依赖包含了feign-form和feign-form-spring。
@FeignClient(value = "feign2", configuration = Feign2Service.MultipartSupportConfig.class)
public interface Feign2Service {
@PostMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
String handleFileUpload(@RequestPart(value = "file") MultipartFile file);
@Configuration
class MultipartSupportConfig{
@Bean
public SpringFormEncoder feignFormEncoder(){
return new SpringFormEncoder();
}
}
}
可以看到,先配置生成了SpringFormEncoder的bean对象,然后在@FeignClient注解中配置configuration值来修改默认Encoder。
这里使用的并不是spring标准的encoder配置,标准配置请看文档 feign-form 或者这篇博文《SpringCloud Feign Decoder》。
通过文档我们可以了解到,Spring Cloud Netflix为feign提供了一些默认配置:
- Decoder : ResponseEntityDecoder (包含了一个SpringEncoder)
- Encoder : SpringEncoder
- Logger : Slf4jLogger
- Controct : SpringMvcControct
- Feign.Builder : HystrixGeign.Builder
- Client : 如果Ribbon可用则为LoadBalancerFeignClient对象,否则若Spring Cloud Balancer可用,则使用FeignBlockingLoadBalancerClient对象,两个都不可用时,则使用默认的feign client。
注意,spring-cloud-starter-openfeign依赖已经同时引入了spring-cloud-starter-netflix-ribbon 和 spring-cloud-starter-loadbalancer。
对于OpenFeign的默认Client : OkHttpClient和ApacheHttpClient,可以通过设置feign.okhttp.enabled 或 feign.httpclient.enabled 值为true进行启用。同时也可以自定义HttpClient。
在之前OpenFeign的使用介绍中,我们了解到OpenFeign有默认的重试器Retryer和对QueryMap的支持。但是Spring Cloud OpenFeign并没有对以下配置进行默认实现:
- Logger.Level
- Retryer
- ErrorDecoder
- Request.Options
- Collection
- SetterFactory
- QueryMapEncoder
通过以上文件传输方法配置可知,Spring Cloud OpenFeign提供了在@FeignClient注解中设置configuration值来覆盖默认配置的方法。对此我们可以通过该方式来配置以上自实现的Retryer, Interceptor, Logger.Level等。
@Configuration
class Config{
@Bean
public Retryer retryer() {
return new MyRetryer();
}
@Bean
public RequestInterceptor interceptor() {
return new RequestHeaderInterceptor();
}
@Bean
public Logger.Level level() {
return Logger.Level.FULL;
}
}
@FeignClient(value = "feign2", configuration = Feign2Service.Config.class)
public interface Feign2Service {
}
同时,我们也可以通过配置文件的方式对Feign进行配置,在application.yml中进行一下配置:
feign:
client:
config:
feign2:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: full
encoder: feign.form.spring.SpringFormEncoder
requestInterceptors:
- com.example.feign2.interceptor.RequestHeaderInterceptor
注意,config下级为对应feign的名称。
对于所有Feign的默认配置,可以像以上展示的那样通过在@EnableFeignClients注解中设置defaultConfiguration值进行配置,又或者通过配置文件,将config下级对应feign的名称设置为default。
如果同时在注解中设置了Configuration 对象 和在配置文件中进行了配置,此时配置文件的属性值会覆盖注解中的配置。如果想改变此优先级,可以设置feign.client.default-to-properties值为false。
对于OpenFeign日志的支持,在只有log level为debug时,才会输出日志。因此需要在配置文件中设置对应类的日志等级:
logging:
level:
com:
example:
feign2:
service: debug
关于日志等级的分类,在之前的博文中我已经介绍过,在此不再赘述。
关于更多了Spring Cloud OpenFeign的默认配置值,请看文档Common application properties。
@QueryMap
在之前OpenFeign介绍中,我们已经知道OpenFeign使用@QueryMap注解将POJO转换为GET请求参数。但是Spring Clound OpenFeign 并不支持该注解,因为它缺少Value属性。
为此,Spring Cloud OpenFeign提供了一个等效的注解@SpringQueryMap,该注解可以将一个POJO或者是Map参数转换为请求参数。
public class User {
private String uname;
private String pwd;
...getter setter
}
@FeignClient(value = "feign2")
public interface Feign2Service {
@GetMapping("/hi")
String hi(@SpringQueryMap User user);
}
与@QueryMap注解一样,会将POJO的参数名称或者Map的key值作为请求的参数名称。若需要改动,则可以自实现QueryMapEncoder bean。
至此,对Spring Cloud OpenFeign的简单使用及配置已经介绍完毕,接下来我将继续对Sprig Cloud OpenFeign 其他功能特性进行学习总结。
参考资料:
https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.3.RELEASE/reference/html/#feign-querymap-support