Feign是一个声明式的HTTP客户端工具,它简化了在分布式系统中进行服务间通信的过程。开发人员可以使用Feign来定义接口,然后通过该接口来调用远程服务,就像调用本地方法一样简单。
目录
- Feign的一些关键特性和概念:
- openfeign 对比 feign
- Feign
- OpenFeign
- 安装
- Maven安装引入
- 配置
- java config 配置RestTemplate
- 超时配置
- 日志配置
- 开启GZIP
- 使用
- 在`auth` service中定义userClient
- 在`order` service的`helloController`中调用UserClient
- Feign 拦截器
- 总结:
- feign底层会调用restTemplate吗?
- feign底层可以使用哪几种http框架?
Feign的一些关键特性和概念:
-
声明式API:
- 使用Feign,你只需要创建一个Java接口,并使用注解来描述HTTP请求的格式、路径、参数等信息。
- Feign会根据这些注解自动生成一个HTTP客户端的实现,你可以直接调用这个接口来发送HTTP请求。
-
与Spring Cloud集成:
- Feign是Spring Cloud生态系统的一部分,与其他Spring Cloud组件(如Eureka、Ribbon、Hystrix等)无缝集成,可以充分发挥微服务架构的优势。
-
负载均衡:
- Feign集成了Ribbon,可以利用Ribbon的负载均衡功能,将请求分发到多个服务实例中。
-
服务熔断:
- Feign集成了Hystrix,可以通过在Feign接口上添加
@HystrixCommand
注解来实现服务的熔断和降级。
- Feign集成了Hystrix,可以通过在Feign接口上添加
-
动态URL和参数处理:
- Feign允许在运行时动态改变请求的URL,也可以使用
@RequestParam
等注解来处理请求的参数。
- Feign允许在运行时动态改变请求的URL,也可以使用
-
多继承:
- OpenFeign扩展了Feign,支持多继承,可以继承多个Feign接口,实现接口的组合。
-
日志和日志级别:
- Feign提供了日志级别的控制,可以用于调试和监控请求。
-
请求和响应拦截:
- 可以使用
RequestInterceptor
和ResponseInterceptor
来拦截请求和响应,可以用于添加认证信息、记录日志等操作。
- 可以使用
总的来说,Feign是一个强大的工具,使得在微服务架构中进行服务间通信变得非常简单和便捷。通过声明式的API和集成的特性,开发人员可以更加专注于业务逻辑的实现,而不需要手动处理HTTP请求和响应的细节。同时,通过集成Ribbon和Hystrix,Feign也提供了负载均衡和服务熔断的支持,使得微服务架构变得更加健壮和可靠。
openfeign 对比 feign
Feign和OpenFeign都是用于简化在微服务架构中进行服务间通信的工具,它们都属于Spring Cloud生态系统的一部分。
Feign
Feign是Netflix开发的一个声明式的HTTP客户端,它使得编写HTTP客户端变得非常简单。在Feign中,你只需要创建一个接口,然后使用注解来描述HTTP请求的格式、路径、参数等信息,Feign会自动帮你生成实现这个接口的HTTP客户端。
Feign的特点:
- 声明式的API:通过接口定义,使得调用远程服务的代码看起来像调用本地方法一样简单。
- 集成了Ribbon:可以使用Ribbon的负载均衡功能。
- 集成了Hystrix:可以使用Hystrix来实现服务的熔断和降级。
OpenFeign
OpenFeign是Spring Cloud对Feign进行了封装和扩展,提供了一些额外的功能和特性。
OpenFeign相比原始的Feign具有一些优势:
- 支持Spring MVC注解:可以使用Spring MVC的注解,如
@RequestMapping
、@RequestParam
等,使得接口的定义更加灵活。 - 支持多继承:可以继承多个Feign接口,实现接口的组合。
- 支持动态URL:可以在运行时动态改变请求的URL。
总的来说,OpenFeign是对Feign的增强和扩展,提供了更多的灵活性和便利性,使得微服务之间的通信更加方便和高效。
在实际项目中,如果你使用了Spring Cloud,通常会优先选择使用OpenFeign来简化服务间的通信。
安装
Maven安装引入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.jorian.framework</groupId>
<artifactId>j-cloud-consumer-feign</artifactId>
<version>1.0.0</version>
<name>j-cloud-consumer-feign</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<cloud.version>Dalston.SR1</cloud.version>
</properties>
<dependencies>
<!-- hystrix断路器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<!--LOMBOK-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
<!-- eureka 配置中心 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- fegin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- boot-web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<!-- dependency management -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
配置
启动类上上注解
package cn.jorian.framework;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
/**
* @author jorian
*/
@SpringCloudApplication
@EnableEurekaClient // 表明这是一个eureka客户端
@EnableFeignClients(basePackages = "cn.jorian.*") //开启feign
public class JCloudConsumerFeignApplication {
public static void main(String[] args) {
// TODO Auto-generated method stub
SpringApplication.run(JCloudConsumerFeignApplication.class, args);
}
}
feign 可以结合nacos、eureka等注册中心使用。当然也可以不适用注册中心,直接在feignClient上指定url来调用,非常的灵活。
java config 配置RestTemplate
RestTemplate配置
@Bean
@LoadBalanced
private RestTemplate restTemplate () {
return new RestTemplate();
}
超时配置
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignConfig {
@Bean
public feign.Request.Options getFeignRequestOptions() {
return new feign.Request.Options(5000, MILLISECONDS, 3000, MILLISECONDS, true);
}
}
也可以通过yml进行配置
feign:
client:
config:
default: # 可以指定具体某个SERVICE,可以替换成service name
connectTimeout: 5000
readTimeout: 3000
日志配置
application.yml
文件中设置日志级别,这个是应用日志的级别要和feign的日志级别配合使用。
logging:
level:
com.csdnblogs.javalouvre.api: debug
application.yml配置feign日志级别,需要指定针对服务名称
feign:
client:
config:
stock-service: # 具体的servicename,可以替换成default全局生效
loggerLevel: FULL
也可以使用javaconfig,下面这个也是全局生效的配置
public class TestConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
开启GZIP
feign:
compression:
request:
enabled: true
mime-types: text/xml,application/xml,application/json # 配置压缩支持的MIME TYPE
min-request-size: 2048 # 配置压缩数据大小的下限
response:
enabled: true # 配置响应GZIP压缩
使用
假入有一个auth service 和一个 order server 现在order service要调用 auth service的UserClient
在auth
service中定义userClient
package cn.jorian.framework.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
/**
* 这个接口相当于把原来的服务提供者项目当成一个Service类
* @author jorian
*
*/
@FeignClient("PROVIDER-USER") // ①
public interface UserClient {
/**
* Feign中没有原生的@GetMapping/@PostMapping/@DeleteMapping/@PutMapping,要指定需要用method进行
*
*
* 接口上方用requestmapping指定是服务提供者的哪个controller提供服务
*/
@RequestMapping(value="/user/sayHello",method=RequestMethod.GET)
public String sayHello();
@RequestMapping(value="/user/sayHi",method=RequestMethod.GET)
public String sayHi();
@RequestMapping(value="/user/sayHaha",method=RequestMethod.GET)
public String sayHaha();
}
① @FeignClient value填写的是服务的名称,feign底层调用的时候会根据服务名称去找eureka、nacos注册列表根据服务名找到注册的实例,拼接成http url进行请求。
在order
service的helloController
中调用UserClient
package cn.jorian.framework.controller;
import cn.jorian.framework.service.UserClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Hellocontroller {
@Autowired
private UserClient feignClient;
/**
* 此处的mapping是一级controller,调用方法里边绑定了二级的conroller,相当于用http完成一次转发
* @return
*/
@GetMapping("/hello")
public String hello(){
return feignClient.sayHello();
}
@GetMapping("/hi")
public String hi(){
return feignClient.sayHi();
}
@GetMapping("/haha")
public String haha(){
return feignClient.sayHaha();
}
}
以一个实例来验证说明效果,自定义三个 RequestInterceptor
class FeignInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("user", "myuser1");
requestTemplate.header("password", "mypassword");
}
}
@FeignClient 中可以指定一个拦截器和feign配置
@FeignClient(
name = "test-service",
url = "http://localhost:8080/feign/server/",
configuration = {FeignInterceptor.class,TestConfiguration.class},
fallback = TestService.DefaultFallback.class
)
Feign 拦截器
RequestInterceptor是拦截器
,可以在发送前做一些处理,比如统一添加header信息。每一类中的requestInterceptors可以存储多个拦截器,拦截器并非覆盖的效果,而是链式追加的效果;从执行顺序来看优先级是:1 > 2 > 3,即先执行配置类中指定的拦截器,然后是配置文件中指定的全局拦截器,最后是配置文件中指定的专属拦截器。
需特别注意:RequestInterceptor的实现类(例如 RI-A,RI-B)上如果添加了@Component注解,就都会被扫描识别到,并被追加到第一类的requestInterceptors列表中;倘若不小心 RI-A 还在第 2 类中又被指定了,则还会将拦截器 RI-A 追加在第二类的requestInterceptors列表中,结果是会 RI-A 总计会执行 2 次;若也在第三类中指定 RI-A,则 RI-A 也在其列表中追加,结果是 RI-A 总计会执行 3 次。
总结:
feign底层会调用restTemplate吗?
是的,Feign在底层使用了RestTemplate来发送HTTP请求。RestTemplate是Spring框架提供的一个用于发送HTTP请求的工具类,它提供了许多便捷的方法来处理HTTP请求和响应。
Feign通过将接口的方法映射到HTTP请求,使得你可以以一种声明式的方式调用远程服务。Feign会将这些方法调用转换为相应的HTTP请求,并使用RestTemplate来实际发送请求。
然而,需要注意的是,随着Spring Cloud的发展,RestTemplate正在逐渐被WebClient取代。WebClient是一个非阻塞、响应式的HTTP客户端,适用于构建响应式的、高性能的分布式系统。因此,如果你使用了Spring Cloud的最新版本,可能会更倾向于使用WebClient而不是RestTemplate。
如果你使用的是旧版本的Spring Cloud或者有特定的需求需要使用RestTemplate,那么Feign将会继续使用它作为发送HTTP请求的底层工具。
feign底层可以使用哪几种http框架?
okHttp/apache httpClient/HttpUrlConnection