热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

SpringCloudFeign实例讲解学习

这篇文章主要介绍了SpringCloudFeign实例讲解学习,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

前面博文搭建了一个Eureka+Ribbon+Hystrix的框架,虽然可以基本满足服务之间的调用,但是代码看起来实在丑陋,每次客户端都要写一个restTemplate,为了让调用更美观,可读性更强,现在我们开始学习使用Feign。

Feign包含了Ribbon和Hystrix,这个在实战中才慢慢体会到它的意义,所谓的包含并不是Feign的jar包包含有Ribbon和Hystrix的jar包这种物理上的包含,而是Feign的功能包含了其他两者的功能这种逻辑上的包含。简言之:Feign能干Ribbon和Hystrix的事情,但是要用Ribbon和Hystrix自带的注解必须要引入相应的jar包才可以。

案例一:

Eureka注册中心:https://github.com/yejingtao/forblog/tree/master/demo-eureka-register

服务提供方:https://github.com/yejingtao/forblog/tree/master/demo-feign-freeservice

服务调用方:https://github.com/yejingtao/forblog/tree/master/demo-feign-freeconsumer

服务提供方就是个简单的EurekaClient端+web应用,提供以下方法

@RestController 
@RequestMapping("/feign-service") 
public class HelloServiceContorller { 
  private Logger logger = LoggerFactory.getLogger(this.getClass());    
  private void sleep(String methodName) { 
    int sleepMinTime = new Random().nextInt(3000); 
    logger.info("helloService "+methodName+" sleepMinTime: "+sleepMinTime); 
    try { 
      Thread.sleep(sleepMinTime); 
    } catch (InterruptedException e) { 
      e.printStackTrace(); 
    } 
  } 
   
  @RequestMapping(value="/serviceGet",method=RequestMethod.GET) 
  public String helloService(@RequestParam String name) { 
    sleep("get"); 
    return "HelloServiceImpl name :"+name; 
  } 
   
  @RequestMapping(value="/serviceHead", method=RequestMethod.HEAD) 
  public String helloService(@RequestHeader String name, 
      @RequestHeader String password) { 
    sleep("header"); 
    return "helloServiceHead name :"+name +" password:"+password; 
  } 
   
  @RequestMapping(value="/servicePost", method=RequestMethod.POST) 
  public String helloService(@RequestBody UserDemo userDemo) { 
    sleep("post"); 
    return userDemo.toString(); 
  } 
} 

需要注意的以下注解不可以省略。

@RequestParam:Annotation which indicates that amethod parameter should be bound to a web request parameter

@RequestBody:Annotation indicating a methodparameter should be bound to the body of the web request.

@RequestHeader:Annotation which indicates that amethod parameter should be bound to a web request header.

如果缺少了以上注解,服务运行起来以后虽然不会报错,但是获取不到入参。

服务调用方项目:

 
      org.springframework.cloud 
      spring-cloud-starter-feign 
     

这里只依赖了Feign,没有依赖Ribbon和Hystrix。

application.yml:

server: 
 port: 9051 
 
spring: 
 application: 
  name: demo-feign-freeconsumer 
   
eureka: 
 client: 
  serviceUrl: 
   defaultZone: http://peer1:1111/eureka/,http://peer2:1112/eureka/ 
feign: 
 hystrix: 
  enabled: true 
 
#Ribbon 超时时间设置 
#ribbon: 
# ConnectTimeout: 500 
# ReadTimeout: 3000

hystrix这个配置坑了我好久我用的Spring Cloud是Dalston版本SR1,比网上其他材料的版本要新,因为在新版本中Feign对Hystrix的支持默认是关闭的,所以要通过配置手动打开feign.hystrix.enabled=true,这样服务降级等功能才有效果。

Application启动程序

@SpringBootApplication 
@EnableEurekaClient 
@EnableFeignClients 
public class DemoFeignApplication {    
  public static void main(String[] args) { 
    SpringApplication.run(DemoFeignApplication.class, args); 
  } 
}

注意这里还有个坑,我这里用的是@SpringBootApplication+@EnableEurekaClient,而不是用的@SpringCloudApplication,因为后者包含了@EnableCircuitBreaker,而@EnableCircuitBreaker又是属于Hystrix包里的内容,我的pom里并没有引入Hystrix。所以这一点Spring Cloud做的还是有不足的地方,直接用@SpringCloudApplication编译不会报错,但是启动不了。当然这里的主角还是@EnableFeignClients这个注解。

核心客户端代码

@FeignClient(name="demo-feign-freeservice",fallback=DemoFeignFallback.class) 
public interface DemoFeignService{ 
    
  @RequestMapping(value="/feign-service/serviceGet",method=RequestMethod.GET) 
  String helloService(@RequestParam("name") String name); 
   
  @RequestMapping(value="/feign-service/serviceHead", method=RequestMethod.HEAD) 
  String helloService(@RequestHeader("name") String name, 
      @RequestHeader("password") String password); 
   
  @RequestMapping(value="/feign-service/servicePost", method=RequestMethod.POST) 
  String helloService(@RequestBody UserDemo userDemo);  
} 

@FeignClient注解定义了该接口是一个Feign客户端,name指定了注册到Eureka上的服务名,fallback是服务降级后的接口实现类。

@RequestMapping里指定了请求的相对url和http请求方式,与服务端一一对应。入参里的@RequestParam、

@RequestBody、@RequestHeader注解比起服务端多了value属性,这里不能省略,需要显式的告知Feign客户端参数要如何对应。

降级服务代码:

@Component 
public class DemoFeignFallback implements DemoFeignService{ 
  @Override 
  public String helloService(String name) { 
    return "get error"; 
  } 
 
  @Override 
  public String helloService(String name,String password) { 
    return "head error"; 
  } 
   
  @Override 
  public String helloService(UserDemo userDemo) { 
    return "post error"; 
  } 
} 

发现这里的入参里我故意去掉了@RequestParam、@RequestBody、@RequestHeader注解,因为这几个注解本质上的意义就在于Feign在做微服务调用的时候对http传递参数用的,但服务降级根本不会做http请求了,所以此处可以省略。

Controller代码:

@RestController 
public class DemoFeignController {    
  @Autowired 
  private DemoFeignService demoFeignService;    
  @RequestMapping(value="/test", method=RequestMethod.GET) 
  public String demoServiceTest() { 
    StringBuffer sb = new StringBuffer(); 
    sb.append(demoFeignService.helloService("yuanyuan")); 
    sb.append("\n"); 
    sb.append(demoFeignService.helloService("yjt","xixihaha")); 
    sb.append("\n"); 
    sb.append(demoFeignService.helloService(new UserDemo("yejingtao","123456"))); 
    return sb.toString();      
  } 
} 

我们来看效果:

我们服务都没超时,3个方法全部正常,但是head请求没有拿到返回值,这个是因为head方式http请求的特性决定的,head不返回response的body体,一般用来做连通性测试来用。

再看一组:

运气不好head和post请求方法处理时间超过了2000ms,服务降级,实现被fallback处理类取代。

在案例一中我们总有种感觉,服务提供方和服务调用方存在重复的代码,是否可以进行优化?请看案例二。

案例二:

Eureka注册中心:https://github.com/yejingtao/forblog/tree/master/demo-eureka-register

接口API:https://github.com/yejingtao/forblog/tree/master/demo-feign-serviceapi

服务提供方:https://github.com/yejingtao/forblog/tree/master/demo-feign-serviceimpl

服务调用方:https://github.com/yejingtao/forblog/tree/master/demo-feign-apiconsumer

案例二最大的变动是将服务能力单独写到一个API的project中,调用方和提供方pom都依赖这个API。

API:

public interface HelloService {    
  @RequestMapping(value="/feign-service/serviceGet",method=RequestMethod.GET) 
  String helloService(@RequestParam("name") String name); 
   
  @RequestMapping(value="/feign-service/serviceHead", method=RequestMethod.HEAD) 
  String helloService(@RequestHeader("name") String name, 
      @RequestHeader("password") String password); 
   
  @RequestMapping(value="/feign-service/servicePost", method=RequestMethod.POST) 
  String helloService(@RequestBody UserDemo userDemo);    
} 

服务提供方:

@RestController 
public class HelloServiceContorller implements HelloService{    
  private Logger logger = LoggerFactory.getLogger(this.getClass());    
  private void sleep(String methodName) { 
    int sleepMinTime = new Random().nextInt(3000); 
    logger.info("helloService "+methodName+" sleepMinTime: "+sleepMinTime); 
    try { 
      Thread.sleep(sleepMinTime); 
    } catch (InterruptedException e) { 
      e.printStackTrace(); 
    } 
  } 
   
  @Override 
  public String helloService(@RequestParam("name") String name) { 
    sleep("get"); 
    return "HelloServiceImpl name :"+name; 
  } 
   
  @Override 
  public String helloService(@RequestHeader("name") String name, 
      @RequestHeader("password") String password) { 
    sleep("header"); 
    return "helloServiceHead name :"+name +" password:"+password; 
  } 
   
  @Override 
  public String helloService(@RequestBody UserDemo userDemo) { 
    sleep("post"); 
    return userDemo.toString(); 
  }       
} 

服务调用方:

@FeignClient(name="demo-feign-serviceimpl", fallback=FeignServiceFallback.class) 
public interface FeignService extends HelloService{  
} 

其它代码基本不变,效果也一样。

两种风格各有优缺点:freestyle的更自由,服务端新增方法不会影响客户端代码,缺点是服务能力不同步服务能力的变动会引起异常;API格式服务端客户端服务能力同步,但是接口的变动需要修改两边的代码,需要构建的时候就要考虑清楚。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 在Docker中,将主机目录挂载到容器中作为volume使用时,常常会遇到文件权限问题。这是因为容器内外的UID不同所导致的。本文介绍了解决这个问题的方法,包括使用gosu和suexec工具以及在Dockerfile中配置volume的权限。通过这些方法,可以避免在使用Docker时出现无写权限的情况。 ... [详细]
  • EPICS Archiver Appliance存储waveform记录的尝试及资源需求分析
    本文介绍了EPICS Archiver Appliance存储waveform记录的尝试过程,并分析了其所需的资源容量。通过解决错误提示和调整内存大小,成功存储了波形数据。然后,讨论了储存环逐束团信号的意义,以及通过记录多圈的束团信号进行参数分析的可能性。波形数据的存储需求巨大,每天需要近250G,一年需要90T。然而,储存环逐束团信号具有重要意义,可以揭示出每个束团的纵向振荡频率和模式。 ... [详细]
  • 云原生边缘计算之KubeEdge简介及功能特点
    本文介绍了云原生边缘计算中的KubeEdge系统,该系统是一个开源系统,用于将容器化应用程序编排功能扩展到Edge的主机。它基于Kubernetes构建,并为网络应用程序提供基础架构支持。同时,KubeEdge具有离线模式、基于Kubernetes的节点、群集、应用程序和设备管理、资源优化等特点。此外,KubeEdge还支持跨平台工作,在私有、公共和混合云中都可以运行。同时,KubeEdge还提供数据管理和数据分析管道引擎的支持。最后,本文还介绍了KubeEdge系统生成证书的方法。 ... [详细]
  • 学习笔记(34):第三阶段4.2.6:SpringCloud Config配置中心的应用与原理第三阶段4.2.6SpringCloud Config配置中心的应用与原理
    立即学习:https:edu.csdn.netcourseplay29983432482?utm_sourceblogtoedu配置中心得核心逻辑springcloudconfi ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 20211101CleverTap参与度和分析工具功能平台学习/实践
    1.应用场景主要用于学习CleverTap的使用,该平台主要用于客户保留与参与平台.为客户提供价值.这里接触到的原因,是目前公司用到该平台的服务~2.学习操作 ... [详细]
  • 如何用UE4制作2D游戏文档——计算篇
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了如何用UE4制作2D游戏文档——计算篇相关的知识,希望对你有一定的参考价值。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • Skywalking系列博客1安装单机版 Skywalking的快速安装方法
    本文介绍了如何快速安装单机版的Skywalking,包括下载、环境需求和端口检查等步骤。同时提供了百度盘下载地址和查询端口是否被占用的命令。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • [译]技术公司十年经验的职场生涯回顾
    本文是一位在技术公司工作十年的职场人士对自己职业生涯的总结回顾。她的职业规划与众不同,令人深思又有趣。其中涉及到的内容有机器学习、创新创业以及引用了女性主义者在TED演讲中的部分讲义。文章表达了对职业生涯的愿望和希望,认为人类有能力不断改善自己。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
author-avatar
mobiledu2502926443
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有