Feign远程调用,核心就是通过一系列的封装和处理,将以JAVA注解的方式定义的远程调用API接口,最终转换成HTTP的请求形式,然后将HTTP的请求的响应结果,解码成JAVA Bean,返回给调用者。
在消费者工程service-consumer中导入Feign依赖信息:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在消费者工程service-consumer中实现Feign客户端接口:
package com.giser.consumer.feign;
import com.giser.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value="user-service")
public interface UserFeignClient {
@GetMapping("/user/{id}")
User queryById(@PathVariable("id") Long id);
}
package com.giser.consumer.controller;
import com.giser.consumer.feign.UserFeignClient;
import com.giser.consumer.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("cf")
public class ConsumerFeignController {
@Autowired
private UserFeignClient userFeignClient;
@GetMapping("/{id}")
public User queryById(@PathVariable Long id){
return userFeignClient.queryById(id);
}
}
package com.giser.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringCloudApplication
@EnableFeignClients // 开启Feign
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
启动EurekaServer、UserService、ConsumerService服务,访问http://localhost:8081/cf/1进行测试。
在Feign中已经集成了Ribbon依赖和自动配置。
Feign内置的Ribbon默认了请求超时时长为1000,在服务消费工程service-consumer中,可以通过以下配置修改:
ribbon:
ConnectTimeout: 1000 # 连接超时时长
ReadTimeout: 2000 # 数据通信超时时长
MaxAutoRetries: 0 # 当前服务器的重试次数
MaxAutoRetriesNextServer: 0 # 重试多少次服务
OkToRetryOnAllOperations: false # 是否对所有的请求方式都重试
Ribbon内部有重试机制,如果不希望重试,则可以添加ribbon.OkToRetryOnAllOperations=false配置。
Feign默认也集成了Hystrix,不过默认时关闭的,如需开启可以通过以下配置:
feign:
hystrix:
enabled: true
此时对于Feign中的fallback需要通过类来实现:
package com.giser.consumer.fallback;
import com.giser.consumer.feign.UserClient;
import com.giser.consumer.pojo.User;
import org.springframework.stereotype.Component;
@Component
public class UserClientFallback implements UserClient {
@Override
public User queryById(Long id) {
User user = new User();
user.setId(id);
user.setUsername("用户异常");
return user;
}
}
package com.giser.consumer.feign;
import com.giser.consumer.fallback.UserClientFallback;
import com.giser.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value="user-service", fallback = UserClientFallback.class)
public interface UserClient {
@GetMapping("/user/{id}")
User queryById(@PathVariable("id") Long id);
}
SpringCloud Feign支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。
feign:
compression:
request:
enabled: true # 开启请求压缩
response:
enabled: true
feign:
compression:
request:
enabled: true # 开启请求压缩
mime-types: text/html,application/xml,application/json # 设置压缩的数据类型
min-request-size: 2048 # 设置触发压缩的大小下限
由于@FeignClient 注解修改的客户端在被代理时,都会创建一个新的Fegin.Logger实例,因此通过logging.level.xx=debug 来设置日志级别对Fegin客户端而言不会产生效果,需要额外指定这个日志的级别。
在service-consumer中的yml中配置日志级别:
logging:
level:
com.giser: debug
在service-consumer中编写FeignLogConfig类,定义日志级别:
package com.giser.consumer.config;
import feign.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FeignLogConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
Feign支持四种Level级别,包括:
NONE:不记录任何日志信息,这是默认值。
BASIC:仅记录请求的方法,URL以及响应状态码和执行时间
HEADERS:在BASIC的基础上,额外记录了请求和响应的头信息
FULL:记录所有请求和响应的明细,包括头信息、请求体、元数据。
在@FeignClient注解中指定配置类:
package com.giser.consumer.feign;
import com.giser.consumer.config.FeignLogConfig;
import com.giser.consumer.fallback.UserClientFallback;
import com.giser.consumer.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value="user-service", fallback = UserClientFallback.class, configuration = FeignLogConfig.class)
public interface UserClient {
@GetMapping("/user/{id}")
User queryById(@PathVariable("id") Long id);
}
重启项目,进行服务访问,可以看到类似如下日志信息:
[UserClient#queryById] ---> GET http://user-service/user/3 HTTP/1.1
[UserClient#queryById] Accept-Encoding: deflate
[UserClient#queryById] Accept-Encoding: gzip
[UserClient#queryById] ---> END HTTP (0-byte body)
[UserClient#queryById] <--- HTTP/1.1 200 (888ms)
[UserClient#queryById] content-type: application/json;charset=UTF-8
[UserClient#queryById] date: Sat, 16 Oct 2021 05:51:53 GMT
[UserClient#queryById] transfer-encoding: chunked
[UserClient#queryById]
[UserClient#queryById] {"id":3,"username":"wangwu","password":"666"}
[UserClient#queryById] <--- END HTTP (45-byte body)