作用
服务消费方基于rest方式请求服务提供方的服务时,一种直接的方式就是自己拼接url,拼接参数然后实现服务调用,但每次服务调用都需要这样拼接,代码量复杂且不易维护,此时Feign诞生。
什么是feign
feign方式的远程服务调用,底层会自动基于ribbon组件实现负载均衡。
ribbon是一个负载均衡组件,是Ribbon组件中提供了IRule接口及相关实现
Feign 是一种声明式Web服务客户端,底层封装了对Rest技术的应用,通过Feign可以简化服务消费方对远程服务提供方法的调用实现。如图所示:
Feign应用过程分析(底层逻辑先了解):
1)通过 @EnableFeignCleints 注解告诉springcloud,启动 Feign Starter 组件。
2) Feign Starter 会在项目启动过程中注册全局配置,扫描包下所由@FeignClient注解描述的接口,然后由系统底层创建接口实现类(JDK代理类),并构建类的对象,然后交给spring管理(注册 IOC 容器)。
3) Feign接口被调用时,底层代理对象会将接口中的请求信息通过编码器创建 Request对象,基于此对象进行远程过程调用。
4) Feign客户端请求对象会经Ribbon进行负载均衡,挑选出一个健康的 Server 实例(instance)。
5) Feign客户端会携带 Request 调用远端服务并返回一个响应。
6) Feign客户端对象对Response信息进行解析然后返回客户端。
第一步:在服务消费方,添加项目依赖(SpringCloud团队基于OpenFeign研发了starter),代码如下:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
第二步:在启动类上添加@EnableFeignClients注解,代码如下:
/*
* @EnableFeignClients 注解用于描述一些配置类,
* 告诉系统底层启动时为@FeignClient注解描述的接口创建实现类及对象,
* 然后交给Spring管理
* */
@SpringBootApplication
@EnableFeignClients
public class ConsumerApplication {
第三步:定义Http请求API,基于此API借助OpenFeign访问远端服务,代码如下:
/*
* @FeignClient注解用于描述远程服务调用接口,其value属性值有两个层面的含义:
* 第一个含义就是要你要的远程服务名,第二个含义就是但钱Bean的名字
* contextId指定Bean的名字
* */
@FeignClient(value = "sca-provider")
public interface RemoteProviderService {
@GetMapping("/provider/echo/{string}")//feign中@PathVariable必须要指定
String echoMassage(@PathVariable("string") String string);
}
其中,@FeignClient描述的接口底层会为其创建实现类。
第四步:创建FeignConsumerController中并添加feign访问,代码如下:
@RestController
@RequestMapping("/consumer")
public class FeignConsumerController {
@Autowired
private RemoteProviderService remoteProviderService;
@GetMapping("/echo/{msg}")
public String doFeignEcho(@PathVariable String msg){
return remoteProviderService.echoMassage(msg);
}
}
一个服务提供方通常会提供很多资源服务,服务消费方基于同一个服务提供方写了很多服务调用接口,此时假如没有指定contextId,服务启动就会失败,例如,假如在服务消费方再添加一个如下接口,消费方启动时就会启动失败:报错信息:
The bean 'optimization-user.FeignClientSpecification', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled.
解决方案:此时我们需要为远程调用服务接口指定一个contextId,作为远程调用服务的唯一标识(这个标识是Bean对象的名字)即可,例如:
还有,当我们在进行远程服务调用时,假如调用的服务突然不可用了或者调用过程超时了,怎么办呢?一般服务消费端会给出具体的容错方案,例如,在Feign应用中通过FallbackFactory接口的实现类进行默认的相关处理
第一步:定义FallbackFactory接口的实现,代码如下:
第二步:在Feign访问接口中应用FallbackFactory对象,例如:
第三步:在配置文件application.yml中添加如下配置,启动feign方式调用时的服务中断处理机制.
第四步:在服务提供方对应的调用方法中添加Thread.sleep(5000)模拟耗时操作,然后启动服务进行访问测试.
为什么使用feign?(基于Feign可以更加友好的实现服务调用,简化服务消费方对服务提供方方法的调用)。
@FeignClient注解的作用是什么?(告诉Feign Starter,在项目启动时,为此注解描述的接口创建实现类-代理类)
Feign方式的调用,底层负载均衡是如何实现的?(Ribbon)
@EnableFeignCleints 注解的作用是什么?(描述配置类,例如启动类)