Spring Cloud 之OpenFeign
Spring Cloud 之OpenFeign
一:简介
Feign是一个声明式(对比RestTemplate编程式)的服务客户端,即通过@FeignClient注解即可声明一个接口(interface)。还支持多种插拔式的配置如encoders/decoders(加解码),clients(不同的链接框架)...... 。Spring Cloud 集成了 Eureka、Spring Cloud Breaker 以及 Spring Cloud LoadBalancer,便可实现 Feign 负载平衡的 http 客户端。
二: 使用方式一(单独使用)
2.1:引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
<version>??feign.version??</version>
</dependency>
2.2:定义接口
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
public static class Contributor {
String login;
int contributions;
}
2.3 : 构造Feign的 http 客户端 示例
public class MyApp {
public static void main(String... args) {
GitHub github = Feign.builder()
.decoder(new GsonDecoder())
.target(GitHub.class, "https://api.github.com");
List<Contributor> contributors = github.contributors("OpenFeign", "feign");
for (Contributor contributor : contributors) {
System.out.println(contributor.login + " (" + contributor.contributions + ")");
}
}
}
示例解释:
2.3.1 :接口地址‘ https://api.github.com/repos/OpenFeign/feign/contributors’是一个获取github上OpenFeign项目的贡献者名单信息。
2.3.2 :Feign.builder(构建者模式(23种设计模式之一)).decoder指定解析器(返回的是json数组).target指定指定目标对象(接口和url)
2.3.3 :自定义其他参数
.encoder(加析器),errorDecoder(异常解析器).client(指定使用的客户端)....再次不一一介绍。
小结: 通过简介以及一个简单的示例,我们已经明了了Feign用法和架构,下面就看springcloud如何集成Feign
三:springcloud集成Feign
3.1:启动类加@EnableFeignClients注解开启声明式Feign,
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
3.2: 通过interface定义接口地址(复用2.2:定义接口)
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
3.3:通过@FeignClient注解(相当于 Feign.builder()) 定义远程服务地址和其他组件
@FeignClient(url = "服务名地址(https://api.github.com)" ,value = "服务名(springboot项目的项目名与url二选一)")
interface GitHub {
@RequestLine("GET /repos/{owner}/{repo}/contributors")
List<Contributor> contributors(@Param("owner") String owner, @Param("repo") String repo);
}
四:集成feign后的常见需求
4.1 Feign调用失败后的错误分析
fallbackFactory :错误后的返回信息 推荐使用相比fallback可辨知错误原因)
fallback:错误后的返回信息
#配置文件中需开启错误分析
feign:
hystrix: # 老版本
enabled: true
circuitbreaker: #新版本
enabled: true
# If true, an OpenFeign client will be wrapped with a Hystrix circuit breaker,Hystrix的默认隔离级别事线程,故feign的拦截器与调用不在同一个线程内
4.1.2 fallbackFactory 示例
@Component
public class FallbackFactoryGitHub implements FallbackFactory<GitHub> {
private static final Logger logger = LoggerFactory.getLogger(GitHub.class);
@Override
public GitHub create(Throwable throwable) {
return new GitHub() {
@Override
public String contributors( String owner, String repo) {
logger.error("contributors", throwable);
return throwable.getMessage();
}
.....
};
}
}
4.2 服务间通过Feign调用,会丢失请求头的信息()
4.2.1 步骤一:定义RequestInterceptor传的请求头信息:
@Bean
public RequestInterceptor headerInterceptor() {
return template -> {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//(feign.hystrix.enabled: true) attributes 为 null
if (null != attributes) {
attributes.getRequest();
HttpServletRequest request = attributes.getRequest();
Enumeration<String> headerNames = request.getHeaderNames();
if (headerNames != null) {
while (headerNames.hasMoreElements()) {
String name = headerNames.nextElement();
String values = request.getHeader(name);
// 跳过 content-length
if (name.equals("content-length")){
continue;
}
template.header(name, values);
}
}
}
};
}
4.2.2 指定配置
@FeignClient(.... , configuration = XXX.class)
五:参考资料
5.1 https://docs.spring.io/spring-cloud-openfeign/docs/3.1.8/reference/html
5.2 https://github.com/OpenFeign/feign
最后期待负载均衡客户段是如何实现的