1.Feign是什么
Feign是一个声明式WebService客户端。使用Feign能让编写Web Service客户端更加简单,.它的使用方法是定义一个接口,然后在上面添加注解。
Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡。
Feign的底层就是Ribbon
2.Feign能干什么
Feign旨在使编写Java Http客户端变得更容易。
封装了Http调用流程,更适合面向接口化的变成习惯
前面在使用Ribbon+RestTemplate时,利用RestTemplate对http请求的封装处理,形成了一套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用
所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。
在Feign的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。
3.Feign结合Ribbon
Spring Cloud集成了Ribbon和Eureka,可在使用Feign时提供负载均衡的http客户端。
利用Ribbon维护了服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,通过feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用
4.Feign的设计流程
5.Feign的实践
pom.xml文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
Feign的底层是使用rabbon作为负载均衡的客户端,而ribbon的负载均衡依赖eureka 获得各个服务的地址,所以如果想实现feign的负载均衡,要引入eureka。如果另有插件负责负载均衡,那可以不用引入。
主启动类用@FeignClient和@EnableEurekaClient注释
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Application
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer80_Feign_App.class, args);
}
}
feign的配置,这一步非必要,如果想配置一些http相关字段,比如连接超时,读取超时可以配置,除了下列属性,还有其他相关属性。请注意,如果你同时设置了rabbon和feign的配置,feign的配置会生效。如果你设置了@FeignClient注解的 url 参数,此时 ribbon 设置的超时时间将会失效,但是通过 Feign 设置的超时时间不会受到影响(仍然会生效)
application.yaml
feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 5000
loggerLevel: basic
Feign的使用
@FeignClient(value = "CART")
public interface CartFeignClient {
@PostMapping("/cart/{productId}")
Long addCart(@PathVariable("productId")Long productId);
}
如接口类一样般声明一个http接口,调用的时候按传统的springbean注入就能调用了。此处是引用了eureka注册的服务,feign将会去调用eureka注册的。如果是没有注册中心,想像一个普通的http工具一样的话,需要加上url属性。
6.FeignClient注解的一些属性
属性名 | 默认值 | 作用 | 备注 |
---|---|---|---|
value | 空字符串 | 调用服务名称,和name属性相同 | |
serviceId | 空字符串 | 服务id,作用和name属性相同 | 已过期 |
name | 空字符串 | 调用服务名称,和value属性相同 | |
url | 空字符串 | 全路径地址或hostname,http或https可选 | |
decode404 | false | 配置响应状态码为404时是否应该抛出FeignExceptions | |
configuration | {} | 自定义当前feign client的一些配置 | 参考FeignClientsConfiguration |
fallback | void.class | 熔断机制,调用失败时,走的一些回退方法,可以用来抛出异常或给出默认返回数据。 | 底层依赖hystrix,启动类要加上@EnableHystrix |
path | 空字符串 | 自动给所有方法的requestMapping前加上前缀,类似与controller类上的requestMapping | |
primary | true |
7.Feign 自定义处理异常
feign可以自定义调用服务出错的异常处理类,只要实现ErrorDecoder类的decode方法,然后在application配置类配置上该类是feign的异常处理类即可
public class FeignDefaultErrorDecoder implements ErrorDecoder {
public Exception decode(String methodKey, Response response) {
String body = "";
ErrorResponseBean standard = null;
try {
if (response.body() != null) {
body = Util.toString(response.body().asReader());
standard = JsonUtils.parseJson(body, ErrorResponseBean.class);
}
} catch (Exception ignored) {
}
String msg = String.format("status %s reading %s", new Object[]{Integer.valueOf(response.status()), methodKey});
msg += "; content:\n" + body;
return new UnexpectedErrorResponse(msg, ImmutableMap.of("response", response, "status", response.status(), "content", body));
}
}
配置类
feign.client.config.default.error-decoder=com.metals.user.config.web.FeignDefaultErrorDecoder
8.Feign底层支持的客户端
feign底层支持三种客户端,每种客户端都对应这feign在进行http请求时采用的不同客户端请求方式。除了这三种,还有一个客户端是这三种的包装。
- Client.Default
Feign 的默认的客户端,如果没有特别指定,将会是这个。内部使用JDK的HttpURLConnnection 来处理 HTTP URL 的请求 - .HttpClient(ApacheHttpClient)
Feign 将会通过 feign.httpclient.ApacheHttpClient(基于 Apache httpclient 开源组件) 来处理 HTTP URL 的请求 - OkHttpClient
Feign 将会通过 feign.okhttp.OkHttpClient(基于 Okhttp3 开源组件)来处理 HTTP URL 的请求 - LoadBalancerFeignClient
该类作为 Client.Default、ApacheHttpClient、OkHttpClient 的包装类而存在,内部使用 Ribbon 负载均衡算法获取 server 服务器,可以理解 Feign 是通过该类的 LoadBalancerFeignClient.execute(Request request, Options options) 方法将请求转发给真正的客户端(Client.Default、ApacheHttpClient、OkHttpClient)来完成对 HTTP URL 请求的处理
feign的自动配置类有FeignRibbonClientAutoConfiguration和OkHttpFeignLoadBalancedConfiguration等等
9.使用OKhttp发送request
前面说到feign底层有不同客户端,可以通过配置来切换,这里以okhttp为例
maven导入okhttp
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
application配置类
feign.httpclient.enabled=false
feign.okhttp.enabled=true
定义一个配置类
@Configuration
@ConditionalOnClass(Feign.class)
@AutoConfigureBefore(FeignAutoConfiguration.class)
public class FeignOkHttpConfig {
@Bean
public okhttp3.OkHttpClient okHttpClient(){
return new okhttp3.OkHttpClient.Builder()
.readTimeout(60, TimeUnit.SECONDS)
.connectTimeout(60, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS)
.connectionPool(new ConnectionPool())
.build();
}
}
10.Feign原理简述
- 启动时,程序会进行包扫描,扫描所有包下所有@FeignClient注解的类,并将这些类注入到spring的IOC容器中。当定义的Feign中的接口被调用时,通过JDK的动态代理来生成RequestTemplate。
- RequestTemplate中包含请求的所有信息,如请求参数,请求URL等。
- RequestTemplate生成Request,然后将Request交给client处理,这个client默认是JDK的HTTPUrlConnection,也可以是OKhttp、Apache的HTTPClient等。
- 最后client封装成LoadBaLanceClient,结合ribbon负载均衡地发起调用。
11.Feign Client的配置方式
方式一,如上面那样,可以直接配置在application配置文件
feign:
client:
config:
default:
connectTimeout: 5000 #连接超时
readTimeout: 5000 #读取超时
loggerLevel: basic #日志等级
方式二,通过配置类去绑定
@EnableFeignClients注解上有个defaultConfiguration属性,可以指定默认Feign Client的配置类
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration.class)
@EnableDiscoveryClient
@SpringBootApplication
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}
DefaultFeignConfiguration内容:
@Configuration
public class DefaultFeignConfiguration {
@Bean
public Retryer feignRetryer() {
return new Retryer.Default(1000,3000,3);
}
}
11.Feign Client的开启日志
正常的系统需要日志去维护,对于一个服务,想要知道调用日志流程可以有两种方式,一种是传统的interceptor+spring的HttpMessageConverter,可以得到这个服务被人调用和返回的流程日志。对于feign来说,可以配置开启日志,能直接看到这个服务调用别的服务的相关日志。
这种开启feign配置的方式有两种,与上面差不多,一种配置类,一种配置文件
1.配置类
@Configuration
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.BASIC;
}
}
2.配置文件
logging:
level:
com.xt.open.jmall.product.remote.feignclients.CartFeignClient: debug
12.OpenFeign和Feign
对于openFeign和feign在学习中是疑惑最大的点,其实咱们现在通常使用的都是openFeign。
Ribbon
Ribbon 是 Netflix开源的基于HTTP和TCP等协议负载均衡组件
Ribbon 可以用来做客户端负载均衡,调用注册中心的服务
Ribbon的使用需要代码里手动调用目标服务,使用比较繁琐的RestTemplate
Feign
一个轻量级RESTful的HTTP服务客户端
Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。
Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务
请注意!!Feign本身不支持Spring MVC的注解,它有一套自己的注解,是Feign的特有注解来定义接口,而这套已经停止更新了
OpenFeign
在feign的基础上支持了springMVC的注解,也就是@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。