一,理解Feign
1,什么是Feign
Netflix Feign
Feign是Netflix开发的声明式、模板化的HTTP客户端, Feign可以帮助我们更快捷、优雅地调用HTTP API。
Feign实际上是对普通HTTP客户端的一层封装,其目的是降低集成成本、提升可靠性。Feign支持三种HTTP客户端,包括JDK自带的HttpURLConnection、Apache HttpClient和Square OkHttp,默认使用Apache HttpClient。
Spring Cloud Feign
Spring Cloud Feign是基于Netflix Feign实现,对Netflix Feign进行了增强,使Feign支持了Spring MVC注解,整合了Spring Cloud Ribbon和Spring Cloud Hystrix 提供负载均衡和断路器。
2,Feign和Open Feign
其实Feign和Open Feign他俩是属于同一个东西,Feign仅仅只是改名成为了
Open Feign而已,然后Open Feign项目在其基础上继续发展至今。
spring-cloud-starter-feign 从1.2.0.RELEASE
开始 已放弃Netflix Feign而全面使用更新的Open Feign版本,
spring-cloud-starter-openfeign更是和Netflix Feign已经没有关系了。
二,Feign的使用
1,服务消费方使用
1.1,起一个eureka服务:
1.2,向eureka-server中注册一个服务提供者eureka-provider
application.yaml
spring:
application:
name: eureka-provider
eureka:
client:
service-url:
defaultZone: http://euk-server1:7001/eureka/
instance:
hostname: euk-client1
HelloController.java
@RestController
public class HelloController {
@Value("${server.port}")
private String port;
@GetMapping("/testFeign")
public String testFeign() {
System.out.println("port:" + port);
return "服务提供者,端口为:" + port;
}
}
1.3,使用Feign向eureka-server注册服务消费者
导入Open Feign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置appliation.yml 注册到Eureka Server。
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://euk-server1:7001/eureka/
spring:
application:
name: eureka-consumer
server:
port: 7008
使用@FeignClient为本应用声明一个简单的能调用的客户端,value是需要调用的服务名。
@FeignClient(value = "eureka-provider")
public interface FeignInterface {
@RequestMapping("/testFeign")
public String testFeign();
}
接收外部请求,通过Feign远程调用服务
@RestController
public class FeignController {
@Autowired
private FeignInterface feignInterface;
@RequestMapping("/testFeign")
public String testFeign() {
return feignInterface.testFeign();
}
}
在启动类上添加 @EnableFeignClients 启用 Feign
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class EurekaConsumer1Application {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumer1Application.class, args);
}
}
启动eureka-consumer然后访问http://localhost:7008/testFeign 返回结果:
2,Fegin的继承特性使用
Spring Cloud Feign提供了继承特性,所谓的继承特性就是将一些公共操作提取到一个父接口中,从而继承父接口中的操作,减少代码的重复开发,节约开发成本。
- 编写通用服务接口A,接口方法上写@RequestMapping(),此接口用于 feign。
- 服务提供者 实现上面接口A。
- 服务消费者的feign client接口 继承A。
优点:
可以将接口的定义从 Controller 中剥离,同时配合 Maven 私有仓库就可以轻易地实现接口定义的共享,不用再复制粘贴接口进行绑定,而是实现在构建期的接口绑定,从而有效减少服务客户端的绑定配置。
缺点:
由于接口在构建期间就建立起了依赖,那么接口变动就会对项目构建造成影响,可能服务提供方修改了一个接口定义,那么会直接导致客户端工程的构建失败。
2.1:首先我们新建一个通用model,eureka-feign-api
由于我们要用到spring mvc,所以pom.xml中要依赖spring web模块
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
创建通用接口HelloInterface.java,用于eureka-provider实现,eureka-consumer继承:
@RequestMapping("/feign")
@RestController
public interface HelloInterface {
@GetMapping("/hello")
String hello();
}
2.2:eureka-provider依赖eureka-feign-api并实现其通用接口HelloInterface
eureka-provider的pom添加依赖eureka-feign-api
<dependency>
<groupId>com.bobo</groupId>
<artifactId>eureka-feign-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
eureka-provider的controller实现通用接口HelloInterface
@RestController
public class FeignCommonProviderController implements HelloInterface {
@Value("${server.port}")
private int port;
@Override
public String hello() {
return "服务提供者,我的端口为:" + port;
}
}
eureka-provider启动类
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication.class, args);
}
}
3.3:eureka-consumer依赖eureka-feign-api并继承其通用接口HelloInterface
eureka-consumer的pom依赖添加eureka-feign-api
<dependency>
<groupId>com.bobo</groupId>
<artifactId>eureka-feign-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<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>
eureka-consumer继承通用接口HelloInterface
@FeignClient("eureka-provider")
public interface FeignCommonInterface extends HelloInterface {
}
eureka-consumer通过FeignCommonInterface来实现Feign的调用
@RestController
public class FeignCommonController {
@Autowired
private FeignCommonInterface commonInterface;
@GetMapping("/hello")
public String hello(){
return commonInterface.hello();
}
}
eureka-consumer启动类
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
然后启动eureka-server,eureka-provider,eureka-consumer,通过服务调用eureka-consumer
http://euk-client2:7008/hello 输出:
三,Feign配置
feign的默认配置类是:org.springframework.cloud.openfeign.FeignClientsConfiguration。默认定义了feign使用的编码器,解码器等。
Feign允许自定义配置,自定义配置有如下两种方式:
- 一种是Java 代码配置,需要在@FeignClient(name = “eureka-consumer”,configuration = FeignAuthConfiguration.class)来引用配置。
- 第二种是直接配置文件配置,在application.yml或者application.properties中配置。
1,Java代码配置
public class FeignAutoConfiguration {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("root", "root");
}
}
@FeignClient(value = "eureka-provider",configuration = FeignAutoConfiguration.class)
public interface FeignCommonInterface extends HelloInterface {
}
如果在配置类上添加了@Configuration注解,并且该类在@ComponentScan所扫描的包中,那么该类中的配置信息就会被所有的@FeignClient共享。
最佳实践是:不指定@Configuration注解,而是手动:@FeignClient(name = “eureka-provider”,configuration = FeignAuthConfiguration.class)
2,配置文件配置
自定义拦截器:
/**
* @author bobo
* @date 2020-12-08
* 自定义拦截器
*/
public class MyBasicAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("Authorization", "Basic cm9vdDpyb290");
}
}
application.yaml
spring:
application:
name: eureka-consumer
eureka:
client:
service-url:
defaultZone: http://euk-server1:7001/eureka/
instance:
hostname: euk-client2
server:
port: 7008
feign:
client:
config:
eureka-peovider:
request-interceptors:
com.bobo.eurekaconsumer.MyBasicAuthRequestInterceptor
3,扩展
自定服务名称配置:
feign:
client:
config:
service-valuation:
connect-timeout: 5000
read-timeout: 5000
logger-level: full
通用配置:
feign:
client:
config:
default:
connect-timeout: 5000
read-timeout: 5000
logger-level: full
4,Feign压缩
Spring Cloud Feign 支持请求和响应进行GZIP压缩来提高通信效率,但是会增加CPU压力,建议把最小压缩的文档大小适度调大一点,进行gzip压缩。
# 开启GZIP压缩配置:
#请求GZIP压缩
feign.compression.request.enable=true
#响应GIZP压缩
feign.compression.response.enable=true
#压缩支持的mime type
feign.compression.request.mime-types=text/xml,application/xml.application/json
feign.compression.request.min-request-size=1024
#压缩数据大小的最小值
5,Feign日志
Feign 为每一个FeignClient都提供了feign.logger实例,可在配置中或者java代码中开启日志。
feign:
client:
config:
# 服务名称
eureka-provider:
logger-level: basic
上面logger-level有4种日志类型:
- none:不记录任何日志,默认值。
- basic:仅记录请求方法,url,响应状态码,执行时间。
- headers:在basic基础上,记录header信息。
- full:记录请求和响应的header,body,元数据。
上面的logger-level只对下面的 debug级别日志做出响应:
logging:
level:
com.bobo.eureka-consumer.ServiceForecast: debug
四,写在最后
上述例子代码已上传码云:https://gitee.com/songbozhao/spring-cloud-feign-test