1.概述
当多个模块都需要调用同一个服务下的接口时,可以将Feign接口抽取到公共模块,降低代码冗余和实现代码复用。
2.实现Feign接口的写法
2.1优点
- 可以将服务间调用的接口完全私有化,仅供内部调用;
- 一个Feign接口中可以写同一个服务下的多个controller下的接口方法;
2.2实现步骤
- 公共模块:编写Feign接口
- 被调用模块:实现Feign接口,并在类上加@RestController
- 调用模块:1.启动类加@EnableFeignClients注解,2.yml:feign.sentinel.enable: true
- 服务之间调用参数,使用定义param对象传参,不能使用doamin(仅当前服务中使用)
第一步:编写Feign接口
/**
* 登录Feign接口
*
* @author
* @date 2024/01/31
*/
@FeignClient(value = Constants.Remote.SERVICE_UAA, contextId = "loginApi", fallbackFactory = LoginApiFallbackFactory.class)
public interface LoginApi {
/**
* app登录
*
* @param appLoginParam 应用登录参数
* @return {@link R}<{@link Void}>
*/
@PostMapping(Constants.Remote.PREFIX_LOGIN_REMOTE + "/appLogin")
R<Void> appLogin(@RequestBody @Valid AppLoginParam appLoginParam);
}
第二步:被调用模块:实现Feign接口
注意:一定要加@RestController注解
/**
* 登录API
*
* @author
* @date 2024/01/31
*/
@RestController
public class LoginApiImpl implements LoginApi {
@Autowired
private ILoginService loginService;
/**
* 微信程序登录
*
* @param appLoginParam 应用登录参数
* @return {@link R}<{@link Void}>
*/
@Override
public R<Void> appLogin(@RequestBody AppLoginParam appLoginParam) {
loginService.appLogin(appLoginParam);
return R.success();
}
}
第三步:调用模块注入Feign发起调用
- 导入公共模块的Feign接口
- 启动类加@EnableFeignClients注解
- yml:feign.sentinel.enable: true
3.Fegin工作原理
Feign是一个声明式的http客户端,使用Feign可以实现声明式REST调用,它的目的就是让服务的调用更加简单。Feign整合了SpringMvc注解,这让Feign的客户端接口看起来就像一个Controller。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。
3.1Feign和rest template区别
OpenFeign整合了Ribbon和Hystrix,屏蔽了Ribbon拼接URL,参数的细节,使用声明式编程,让服务调用变得更加简单,OpenFiegn底层也是走的Ribbon的负载均衡策略。推荐使用OpenFeign;
3.2Feign的工作原理
主配置类通过@EnableFeignClients(value="")注解开启Feign,也可以通过value属性指定了Feign的扫描包。同时我们需要为Feign编写客户端接口,接口上需要注解@FeignClient标签。 当程序启动,注解了@FeignClient的接口将会被扫描到然后交给Spring管理。
当请求发起,会使用jdk的动态代理方式代理接口,生成相应的RequestTemplate,Feign会为每个方法生成一个RequestTemplate同时封装好http信息,如:url,请求参数等等
最终RequestTemplate生成request请求,交给Http客户端(UrlConnection ,HttpClient,OkHttp)。然后Http客户端会交给LoadBalancerClient,使用Ribbon的负载均衡发起调用。
3.3Feign的负载均衡原理
在SpringCloud中通过 ClientHttpRequestInterceptor 请求拦截器来连接Feign的请求,其中提供了一个 LoadBalancerClient 来实现负载均衡,他是一个接口,它集成了 ServiceInstanceChooser 接口 ,ServiceInstanceChooser的作用是做服务实例的选择,里面提供了ServiceInstance choose(String serviceId); 方法来根据服务的ID选择一个服务实例(服务提供者做了集群会有多个实例,而一次调用只会执行一个服务实例)。而LoadBalancerClient提供了execute方法去执行服务的调用。
LoadBalancerClient 有一个实现类 BlockingLoadBalancerClient ,来复写 choose 选择实例方法 和 execute调用实例 方法;
在 BlockingLoadBalancerClient 通过调用 ReactiveLoadBalancer #choose(响应式负载均衡器) 方法来选择服务,他有2个子类 RoundRobinLoadBalancer (轮询算法) ,和 RandomLoadBalancer(随机算法) , 默认采用的是RoundRobinLoadBalancer 轮询算法。