目录
1 简介
前面学习中,使用RestTemplate进行远程调用的方式如下:
String baseUrl = "http://user-service/user/findById?id="+ id;
User user = restTemplate.getForObject(baseUrl, User.class)
- RestTemplate虽然已经很简单了,但是还有一些问题:比如仍然需要自己手动把整个请求url拼出来(加了注册中心后不用再手写host+port而改成服务名)而接下来,Feign将帮助我们对调用方式进行优化。
- Feign是一个http请求调用的轻量级框架,是以Java接口的方式调用Http接口,而不用像Java中通过封装HTTP请求报文的方式直接调用。
- Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,进而转化成真正的请求,这种请求相对而言比较直观,再也不用去手动拼写url了。
- Feign中已经自动集成Ribbon负载均衡
2 入门案例与分析
2.1 入门案例
目标:使用Feign替代RestTemplate发送Rest请求,使之更符合面向接口化的编程习惯。
实现步骤
- 导入依赖feign的starter
- 启动引导类加@EnableFeignClients注解
- 编写FeignClient接口,使用SpringMVC的注解
- 在Controller中注入Feign接口,直接调用,无需实现类
- 访问接口测试
1 导入依赖feign的starter :
<!--配置feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2 启动引导类加@EnableFeignClients注解
@SpringCloudApplication
@EnableFeignClients//开启Feign功能
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
3 编写FeignClient接口,使用SpringMVC的注解
- @FeignClient注解会自动生成Feign接口的动态代理实现类,并将其注入到spring容器中
- 接口定义的方法,采用SpringMVC的注解 @RequestMapping
- Feign会根据注解帮我们逆向生成URL地址然后请求
- 在Controller中注入UserService接口,直接调用,无需实现类
FeignClient接口写在工程的service层下:
//声明当前接口是feign客户端的接口,并指定feign调用的服务名为user-service
@FeignClient("user-service")
public interface UserService {
/**
* 接口定义的方法,采用SpringMVC的注解 @RequestMapping
* Feign会通过动态代理,帮我们生成该接口的实现类
* Feign会根据注解帮我们逆向生成URL地址然后请求
* 在Controller中注入UserService接口,直接调用,无需实现类
*/
@RequestMapping("/user/findById")
User findById(@RequestParam("id") Integer id);
}
4 在Controller中注入Feign接口,直接调用,无需实现类
/**
* 通过feign客户端发送请求
*/
@RestController
@DefaultProperties(defaultFallback = "defaultFallBackMethod")
public class FeignConsumerController {
//注入Feign客户端的接口,直接调用
@Autowired
private UserService userService;
@RequestMapping("/feign_consumer/{id}")
public User consumerSendRequest(@PathVariable("id") Integer id){
return userService.findById(id);
}
}
5 测试
http://localhost:8080/feign_consumer/2
2.2 分析Feign的特点
- 复用
哪里需要http调用,就把这个feign接口(整合了某个具体的http调用)注入到哪里,并且这个feign接口上标注了“服务名”以及“被调用服务的上下文”,一旦这些内容发生改动,只需要改一次feign接口即可,而不用每次都跑到具体的方法里面一个个去修改url地址了
- 便于管理
同一个服务下的不同方法调用都放到了一起,便于管理,而不是零散的状态。
- 可读性
可读性更好,更有层次感。
3 Feign 支持负载均衡
- Feign本身集成了Ribbon,因此不需要额外引入依赖,也不需要再注册RestTemplate对象。即可无感知使用负载均衡这一特性。
- Fegin内置Ribbon,默认设置了连接超时为1秒)和读取超时时间。我们可以通过手动配置来修改。
- Ribbon内部有重试机制,一旦超时,会自动重新发起请求。如果不希望重试,可以修改。
# 连接超时时长:必须都要大于服务响应时间,否则一旦设置了熔断则会触发服务降级
ribbon.ConnectTimeout: 6000
# 读取数据超时时长:必须都要大于服务响应时间,否则一旦设置了熔断则会触发服务降级
ribbon.ReadTimeout: 6000
# 当前服务器的重试次数【针对请求】
ribbon.MaxAutoRetries: 0
# 重试多少次服务【针对服务】
ribbon.MaxAutoRetriesNextServer: 0
# 是否对所有的请求方式都重试
ribbon.OkToRetryOnAllOperations: false
4 Feign 支持熔断器
Feign本身也集成Hystrix熔断器,服务降级方法实现步骤:
- 在配置文件application.yml中开启feign熔断器支持(默认关闭)
- 实现FeignClient客户端接口,在实现类中编写FallBack处理类
- 在@FeignClient注解中,指定FallBack处理类
- 测试服务降级效果
- 之前的做法:controller层收到来自浏览器的请求后,直接在方法上用@HystrixCommand来直接指定对应方法的降级方法(或者全局指定)
- 现在的做法:在feign接口上指定了服务降级的处理类,在接口的实现类中编写服务降级的逻辑(感觉这个更合理)
- 关于超时时间的问题请注意:Hystrix中的超时时间和Ribbon中的超时时间(连接和读取数据时间)必须都要大于服务响应时间,否则会触发熔断。
1 在配置文件application.yml中开启feign熔断器支持 :
feign.hystrix.enabled: true # 开启Feign的熔断功能
2 实现FeignClient客户端接口,在实现类中编写FallBack处理类
/**
* feign客户端接口的实现类:直接作为服务降级的处理类
*/
@Component
public class UserServiceImpl implements UserService {
@Override
public User findById(Integer id) {
User user = new User();
user.setUsername("服务降级处理!");
return user;
}
}
3 在@FeignClient注解中,指定FallBack处理类
//声明当前接口是feign客户端的接口,并指定feign调用的服务名为user-service
//该注解会生成接口的动态代理实现类,并将其注入到spring容器中
//fallback属性:指定服务降级的处理类
@FeignClient(value = "user-service",fallback = UserServiceImpl.class)
public interface UserService {
/**
* 接口定义的方法,采用SpringMVC的注解 @RequestMapping
* Feign会通过动态代理,帮我们生成该接口的实现类
* Feign会根据注解帮我们逆向生成URL地址然后请求
* 在Controller中注入UserService接口,直接调用,无需实现类(如果要用熔断,则需要写实现类)
*/
@RequestMapping("/user/findById")
User findById(@RequestParam("id") Integer id);
}
4 测试
http://localhost:8080/feign_consumer/1
5 配置请求与响应压缩
feign:
compression:
# 开启请求压缩
request:
enabled: true
#开启压缩的阈值,默认2048kb
min-request-size: 2048
#压缩的数据类型
mime-types: text/xml, application/xml, application/json
# 开启响应压缩
response:
enabled: true
6 配置日志
- Feign客户端是通过动态代理生成的,Feign支持在java运行时为Feign客户端的动态代理实现类进行日志配置。
- 在发送和接收请求的时候,Feign定义了日志输出的四个等级:
级别 | 说明 |
---|---|
NONE | 不做任何记录 |
BASIC | 只记录输出Http 方法名称、请求URL、返回状态码和执行时间 |
HEADERS | 记录输出Http 方法名称、请求URL、返回状态码和执行时间 和 Header 信息 |
FULL | 记录Request 和Response的Header,Body和一些请求元数据 |
Feign配置日志步骤:
- 在application.yml配置文件中开启日志级别配置
- 编写配置类,定义日志级别bean
- 在接口的@FeignClient中指定配置类
- 重启项目,测试访问
1 在application.yml配置文件中开启日志级别配置
#com.lmy.service 包下的日志级别都为Debug
logging.level.com.lmy.service: debug
2 编写配置类,定义日志级别bean
/**
* Feign客户端接口的配置类
*/
@Configuration
public class FeignConfiguration {
/**
* 注入日志级别的配置到spring容器中
*/
@Bean
public Logger.Level loggerLevel(){
//配置显示全部的日志信息
return Logger.Level.FULL;
}
}
3 在接口的@FeignClient中指定配置类
//声明当前接口是feign客户端的接口,并指定feign调用的服务名为user-service
//该注解会生成接口的动态代理实现类,并将其注入到spring容器中
//fallback属性:指定服务降级的处理类
//configuration属性:指定当前feign客户端的配置类
@FeignClient(value = "user-service",
fallback = UserServiceImpl.class,
configuration = FeignConfiguration.class)
public interface UserService {
/**
* 接口定义的方法,采用SpringMVC的注解 @RequestMapping
* Feign会通过动态代理,帮我们生成该接口的实现类
* Feign会根据注解帮我们逆向生成URL地址然后请求
* 在Controller中注入UserService接口,直接调用,无需实现类(如果要用熔断,则需要写实现类)
*/
@RequestMapping("/user/findById")
User findById(@RequestParam("id") Integer id);
}
4 测试