8

Spring Cloud之Finchley版学习(九)-Feign

 4 years ago
source link: https://www.wencst.com/archives/1347
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Spring Cloud之Finchley版学习(九)-Feign

作者: wencst 分类: JAVA,微服务,架构设计 发布时间: 2019-01-09 09:36 阅读: 1,489 次

经过前文讲解,我们已使用Eureka实现服务发现;使用Ribbon实现了负载均衡这种听起来很高端的东西。我们的架构已经初具雏形,但依然存在很多问题,下面不妨来分析下前文的代码——

@GetMapping("/users/{id}")
public User findById(@PathVariable Long id) {
  // 这里用到了RestTemplate的占位符能力
  User user = this.restTemplate.getForObject(
    "http://microservice-provider-user/users/{id}",
    User.class,
    id
  );
  // ...电影微服务的业务...
  return user;
}

这里,this.restTemplate.getForObject("http://microservice-provider-user/users/{id}"… 这行代码是比较糟糕的,存在诸多问题——

  • 如果系统业务非常复杂,而你是一个新人,当你看到这行代码,恐怕很难一眼看出其用途是什么!此时,你很可能需要寻求老同事的帮助(往往是这行代码的作者,哈哈哈,可万一离职了呢?),或者查阅该目标地址对应的文档(文档常常还和代码不匹配,哈哈哈),才能清晰了解这行代码背后的含义!否则,你只能陷入蛋疼的境地!
  • 这个例子构造的URL非常简单,但如果你需要构造类似如下这么丑陋的URL时(原谅我老是拿百度开涮,其实我没有恶意):https://www.baidu.com/s?wd=asf&rsv_spt=1&rsv_iqid=0xa25bbeba000047fd&issp=1&f=8&rsv_bp=0&rsv_idx=2&ie=utf-8&tn=baiduhome_pg&rsv_enter=1&rsv_sug3=3&rsv_sug1=2&rsv_sug7=100&rsv_sug2=0&inputT=328&rsv_sug4=328 ,恐怕就有心无力了!尽管RestTemplate支持使用占位符,从而让我们避免字符串拼接的尴尬境地,但构造这么复杂的URL依然是很麻烦的。更可怕的是,互联网时代需求变化非常之快,你的参数可能会从10个变成12个、15个,再后来又精简成13个……维护这个URL真的是想想都累……总而言之,复杂URL的构造会让你处于一种不性福的状态

铺垫了这么多,如何解决以上问题?用Feign!

TIPS

  • Feign本质上来说是个山寨,其设计思想基本都来源于Retrofit(使用方式更是如出一辙)
  • Retrofit的GitHub:https://github.com/square/retrofit ,如果你知道Square公司,那么你很厉害!是的,Retrofit也是开源OKHttp的那家公司开源的——所以,笔者喜欢将Square公司称为‘’HTTP客户端小王子”,但其实人家是做移动支付的。
  • Spring Cloud对Retrofit也有支持https://github.com/spring-cloud-incubator/spring-cloud-square ,目前正在孵化中,有兴趣的可以去体验一下。学会Feign后,Retrofit上手也就是5分钟的事情。

Feign是Netflix开发的声明式、模板化的HTTP客户端,其灵感来自Retrofit、JAXRS-2.0以及WebSocket。Feign可帮助我们更加便捷、优雅地调用HTTP API。

在Spring Cloud中,使用Feign非常简单——只需创建接口,并在接口上添加注解即可。

Feign支持多种注解,例如Feign自带的注解或者JAX-RS注解等。Spring Cloud对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便。

TIPS

Feign的GitHub:https://github.com/OpenFeign/feign

Quick Start

下面来将前面的例子用Feign改写,让其达到与Ribbon + RestTemplate相同的效果。

  • 复制项目microservice-consumer-movie,将ArtifactId修改为microservice-consumer-movie-feign
  • 加依赖:
    <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
    </dependency>
  • 加注解:启动类上添加@EnableFeignClients
  • 编写Feign Client:
    @FeignClient(name = "microservice-provider-user")
    public interface UserFeignClient {
      @GetMapping("/users/{id}")
      User findById(@PathVariable("id") Long id);
    }

    这样一个Feign Client就写完啦!其中,@FeignClient 注解中的microservice-provider-user是想要请求服务的名称,这是用来创建Ribbon Client的(Feign整合了Ribbon)。在本例中,由于使用了Eureka,所以Ribbon会把microservice-provider-user 解析成Eureka Server中的服务。

    除此之外,还可使用url属性指定请求的URL(URL可以是完整的URL或主机名),例如@FeignClient(name = "abcde", url = "http://localhost:8000/") 。此时,name可以是任意值,但不可省略,否则应用将无法启动!

  • Controller:
    @RequestMapping("/movies")
    @RestController
    public class MovieController {
      @Autowired
      private UserFeignClient userFeignClient;
      @GetMapping("/users/{id}")
      public User findById(@PathVariable Long id) {
        return this.userFeignClient.findById(id);
      }
    }

    只需使用@Autowire注解,即可注入上面编写的Feign Client。

RestTemplate与Feign对比

相信通过本文的例子,聪明的你对如何使用Feign已经了然于心了。文章的最后,对比一下RestTemplate + Ribbon与Feign。

角度 RestTemplate + Ribbon Feign(自带Ribbon) 可读性、可维护性 欠佳(无法从URL直观了解这个远程调用是干什么的) 极佳(能在接口上写注释,方法名称也是可读的,能一眼看出这个远程调用是干什么的) 开发体验 欠佳(拼凑URL不性福) 极佳(写出漂亮的代码,女朋友更爱你了) 风格一致性 欠佳(本地API调用和RestTemplate调用的代码风格截然不同) 极佳(完全一致,不点开Feign的接口,根本不会察觉这是一个远程调用而非本地API调用) 性能 较好 中等(性能是RestTemplate的50%左右;如果为Feign配置连接池,性能可提升15%左右) 灵活性 极佳 中等(内置功能能满足大多数项目的需求)

那么如何选择呢?相信这才是大家最关注的问题!

笔者认为——

  • 一般来说,建议使用Feign,并杜绝使用RestTmplate。为什么用Feign相信不必啰嗦;可为什么要杜绝RestTemplate,那是因为在一个项目里,保持统一的编码风格乃至体验,是非常重要的。我个人的架构原则是尽量减少开发人员的选择,如果A能解决问题,就杜绝使用B——最佳实践永远只有一个!并且,共存带来的往往不是相得益彰,反而是歧义、错乱以及额外的学习成本、理解成本(笔者当年参与过一个同时使用Struts1 + Struts2 + Servlet的项目,可以想象一下学习成本有多高;笔者还参与一个一个使用Jackson + FastJson + json-lib + Gson的项目,可想而知操作JSON的代码有多混乱……80%的开发在骂娘中度过时光,并抨击别人使用他不熟悉的JSON操作库,后来被笔者统一成Jackson后,大家都安心干活了)!
  • 有人可能会对Feign的性能存在顾虑,笔者认为,Feign的性能虽然不那么优秀,但大部分场景下都是OK的——项目的性能瓶颈一般都不出在HTTP客户端上,而在于自身业务的处理!
  • 求同存异——上文虽说要杜绝RestTemplate,但事无绝对,你得根据具体情况具体分析——对于某些变态需求,在使用Feign很难实现或无法实现时,可考虑使用RestTemplate + Feign共存的方式……Spring Cloud官方也承认,无论Fegin怎么改进,其灵活性也无法比得上RestTemplate!但是,这么做之前请务必慎重,记住,共存带来的往往不是相得益彰,反而是歧义、错乱以及额外的学习成本、理解成本。

GitHub:https://github.com/eacdy/spring-cloud-study/tree/master/2018-Finchley/microservice-consumer-movie-feign

Gitee:https://gitee.com/itmuch/spring-cloud-study/tree/master/2018-Finchley/microservice-consumer-movie-feign


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK