一、背景分析
通过上一篇学习,已经逐渐简化负载均衡的代码实现,但是当我们进行服务调用的时候,每次都需要去拼接url,拼接参,代码量复杂而且难以维护,此时Feign诞生。Feign是一种声明式的WEB服务客户端,底层封装了对REST技术的应用,通过Feign可以简化消费端对远程服务的调用实现,如下图
Fiegn最早由Netflix公司推出,后转为一些社区维护,更名为OpenFeign,本章主要介绍由SpringClound团队基于OpenFeign研发的starter
二、Feign基础应用实践(掌握)
1. 添加SpringClound版本的openfeign依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2. 在启动类或者配置类上添加@EnableFeignClients注解,该注解的作用就是扫描被@FeignClient注解标记的接口,并为该接口创建一个实例对象(代理对象)
3. 在service业务层,定义Http请求API,基于此API借助OpenFeign访问远端服务,代码如下:
package com.jt.consumer.service;
@FeignClient(name="sca-provider")//sca-provider为服务提供者名称
public interface RemoteProviderService{
@GetMapping("/provider/echo/{string}")//前提是远端需要有这个服务
public String echoMessage(@PathVariable("string") String string);
}
@FeignClient注解的作用是标记该接口,底层会为其创建一个实现类代理对象
4. 新建一个feign调用的controller
package com.jt.consumer.controller;
@RestController
@RequestMapping("/consumer/ ")
public class FeignConsumerController {
@Autowired
private RemoteProviderService remoteProviderService;
/**基于feign方式的服务调用*/
@GetMapping("/echo/{msg}")
public String doFeignEcho(@PathVariable String msg){
//基于feign方式进行远端服务调用(前提是服务必须存在)
return remoteProviderService.echoMessage(msg);
}
}
5. 启动消费者服务,在浏览器中直接通过feign客户端进行访问,如图所示
三、Feign进阶配置
一、contextId唯一标识符配置
当我们在使用服务的时候通常情况下,一个服务提供方会提供多个服务,而消费方也会基于一个服务有多个请求接口,此时若不去指定contextId,消费方就会起冲突报错 (因为name="sca-provider"默认有两层含义1、作为服务名2、作为bean注入的对象名,此时若有多个接口调同一个服务,就会多次注入bean导致冲突)。例如在消费方重新添加一个接口去调用sca-provider服务,就会报如下错误
@FeignClient(name="sca-provider")
public interface RemoteOtherService {
@GetMapping("/doSomeThing")
public String doSomeThing();
}
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对象的名字
@FeignClient(name="sca-provider",contextId="remoteProviderService")//sca-provider为服务提供者名称
interface RemoteProviderService{
@GetMapping("/provider/echo/{msg}")//前提是远端需要有这个服务
public String echoMessage(@PathVariable("msg") String msg);
}
2.服务请求超时处理
当我们在调用生产方的服务,而远程服务不可用时,我们需要对其进行处理,避免直接对用户出现报错,这时候我们就需要创建一个服务回调工厂,调用自己本地的一个结果,反馈给客户。
1. 定义定义FallbackFactory接口的实现
package com.jt.consumer.service;
import feign.hystrix.FallbackFactory;
import org.springframework.stereotype.Component;
/**
* 服务回调工厂,当远程的服务不可用时,可以通过配置的方式,调用本地服务返回一个结果
*/
@Component
public class ProviderFallbackFactory implements FallbackFactory<RemoteProviderService> {
@Override
public RemoteProviderService create(Throwable throwable) {
//Lamda表达式写法
// return (msg) ->{
// return "服务维护中";
// } ;
return new RemoteProviderService() {
@Override
public String echoMessage(String msg) {
//这里还可以写自己的的本地服务处理的业务代码,跟运维发短信,服务端报警等等。。。。
return "服务维护中,稍等片刻再访问";
}
};
}
}
2. 在Feign访问接口中应用FallbackFactory对象
@FeignClient(name = "sca-provider", contextId = "remoteProviderService",
fallbackFactory = ProviderFallbackFactory.class)//sca-provider为nacos中的服务名
public interface RemoteProviderService {
@GetMapping("/provider/echo/{msg}")
public String echoMsg(@PathVariable String msg);
}
3. 启动服务的熔断,在配置文件中添加如下配置
feign:
hystrix:
enabled: true #默认值为false
4. 若不想去启动熔断机制也可以去设置时间让程序进行一个超时等待(此时要关闭熔断)
feign:
hystrix:
enabled: false #true,启动服务超时熔断,默认值为false,不开启
client:
config:
default: #这里default指的是全局配置,若是指定某一个服务,这里需要写上服务的名字
connectTimeout: 10000 #请求连接的超时时间,默认值2000
ReadTimeout: 10000 #请求处理超时时间,默认5s