spring cloud 入门系列五:使用Feign 实现声明式服务调用
一、Spring Cloud Feign概念引入
通过前面的随笔,我们了解如何通过Spring Cloud ribbon进行负责均衡,如何通过Spring Cloud Hystrix进行服务断路保护,
两者作为基础工具类框架应用在各种基础设施类微服务和业务类微服务中,并且成对存在,那么有没有更高层的封装,将两者的使用
进一步简化呢? 有! 他就是Spring Cloud Feign。它基于Netflix Feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,
除了提供两者强大的功能外,还提供了一种声明式的Web服务客户端定义方式。
二、入门实例
我们还是继续使用前面随笔中的hello-service服务,这里通过Spring Cloud Feign提供的声明式服务绑定功能来实现对服务接口的调用。
我们需要新建一个feign-consumer来代替之前的hello-consumer
先给出代码结构:
代码实现:
- 新建maven工程(feign-consumer)
- 修改pom文件,引入eureka和feign依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sam</groupId>
<artifactId>feign-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent> <properties>
<javaVersion>1.8</javaVersion>
</properties> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden.SR6</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies> </dependencyManagement> <dependencies>
<!-- 引入eureka 客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!-- 引入feign 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency> </dependencies> </project> - 新建启动类
/**
* 通过@EnableFeignClients来开启spring cloud feign的支持功能
*
*/
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeiApp { public static void main(String[] args) {
SpringApplication.run(FeiApp.class, args);
} } - 新建service接口
/**
* 通过@FeignClient注解指定服务名来绑定服务,这里的服务名字不区分大小写
* 然后再通过@RequestMapping来绑定服务下的rest接口
*
*/
@FeignClient(name="hello-service")
public interface FeignConsumerService{ @RequestMapping("/hello")
public void hello();
} - 新建controller
@RestController
public class FeiConsumerController { @Autowired
FeignConsumerService consumerService; @RequestMapping("feign-consumer")
public String feignConsumer() {
consumerService.hello();
return "feign consumer call finished!!!";
} } - 新建application.properties
server.port=9001 spring.application.name=feign-consumer eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka
- 测试,
- 启动服务注册中心eureka、启动两个hello-service(端口号分别为9090和9091),启动feign-consumer
- 访问http://localhost:9001/feign-consumer
- 启动服务注册中心eureka、启动两个hello-service(端口号分别为9090和9091),启动feign-consumer
并且多次访问的话,会轮询调用两个hello-service服务。
三、参数绑定
在上面的例子中,我们实现的只是一个不带参数的rest服务绑定,然而现实的业务中不会这么简单,往往会有各种参数,
这个时候我们做如下事情:
- 如果服务提供方有对象参数(如User对象),那么feign-consumer工程中需要建一个路径和类名完全一样的类。
- 然后将服务提供方controller里面的所有方法声明进行copy(包括前面的@RequestMapping),粘贴到feign-consumer的service接口里面。
四、继承特性
根据上面参数绑定的做法,我们需要进行很多copy操作,这样比较麻烦,可以通过继承的方式进行简化。
这种实现步骤如下:
1.我们需要新建一个基础工程hello-service-api,
代码结构:
代码实现:
- )新建maven项目hello-service-api
- )修改pom文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sam</groupId>
<artifactId>hello-service-api</artifactId>
<version>0.0.1-SNAPSHOT</version> <parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
</parent> <properties>
<javaVersion>1.8</javaVersion>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependencies>
</project>你会发现其实就是一个普通的spring boot项目。
- )考虑到需要掩饰参数中有对象的情况,我们加个User类
package com.sam.entity; public class User { private String name;
private Integer age; public User(String name, Integer age) {
super();
this.name = name;
this.age = age;
} public User() {
super();
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
} }User必须要有一个无参数的构造器。
- )新建service接口
/**
* 为了同前面那个hello 接口区分开了,我们加了refactor前缀
*
*/
@RequestMapping("/refactor")
public interface HelloService { @RequestMapping("/hello2")
public String hello2(); @RequestMapping("/hello3")
public User printUser(@RequestBody User user);
}
2.重构hello-sevice服务
- )修改pom文件
<!-- 引入 hello-service-api的依赖,以继承其提供的接口 -->
<dependency>
<groupId>com.sam</groupId>
<artifactId>hello-service-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency> - )HelloController implements HelloService,并实现interface中的接口
@RestController
public class HelloController implements HelloService{ Logger logger = LoggerFactory.getLogger(HelloController.class); @Autowired
DiscoveryClient discoveryClient; @RequestMapping("/hello")
public String hello() throws Exception {
ServiceInstance instance = discoveryClient.getLocalServiceInstance();
//打印服务的服务id
logger.info("*********" + instance.getServiceId());
return "hello,this is hello-service";
} @Override
public String hello2() {
return "hello,this is hello2-service"; } @Override
public User printUser(@RequestBody User user) {
return user;
}
}controller实现接口的方法时,不需要@RequestMapping注解,只需要类注解@RestController即可。
3.重构feign-consumer服务
- )修改POM文件
<!-- 引入 hello-service-api的依赖,以继承其提供的接口 -->
<dependency>
<groupId>com.sam</groupId>
<artifactId>hello-service-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency> - )让FeignConsumerService extends hello-service-api中的HelloService
/**
* 通过@FeignClient注解指定服务名来绑定服务,这里的服务名字不区分大小写
* 然后再通过@RequestMapping来绑定服务下的rest接口
*
*/
@FeignClient(name="hello-service")
public interface FeignConsumerService extends HelloService{ @RequestMapping("/hello")
public void hello();
}只需要继承即可。
- )修改controller,追加方法
@RestController
public class FeiConsumerController { @Autowired
FeignConsumerService consumerService; @RequestMapping("feign-consumer")
public String feignConsumer() {
consumerService.hello();
return "feign consumer call finished!!!";
}
@RequestMapping("feign-consumer-user")
public User feignConsumer2(User user) {
consumerService.hello2();
return consumerService.printUser(user);
}
}
4.测试
五、其他
由于Spring Cloud Feign是通过ribbon和hystrix实现具体功能的,因此可以直接通过配置这两个来实现功能
1.ribbon配置方式:
通过ribbon.<key>=<value>的方式进行全局配置,比如
ribbon.ConnectTimeout=500
ribbon.ReadTimeout=5000
通过<client>.ribbon.<key>=<value>的方式进行指定服务配置,比如
#这里的<client>为@FeignClient(value="hello-service")指定的服务名
hello-service.ribbon.ConnectTimeout=500
hello-service.ribbon.ReadTimeout=500
2.hystrix配置方式:
通过hystrix.command.default.xxx进行全局配置
如:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
通过hystrix.command.<commandKey>.xxx进行指定配置,这里的<commandKey>可以为方法名
如:hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000
3.请求压缩配置,支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。
feign.compression.request.enabled=true;
feigan.compression.response.enabled=true;
4.日志配置
Spring Cloud Feign在构建被@FeignClient注解修饰的服务客户端是,会为每一个客户端都创建一个feign.Logger实例,我们可以利用该日志对象进行Log分析。
spring cloud 入门系列五:使用Feign 实现声明式服务调用的更多相关文章
- SpringCloud系列-利用Feign实现声明式服务调用
上一篇文章<手把手带你利用Ribbon实现客户端的负载均衡>介绍了消费者通过Ribbon调用服务实现负载均衡的过程,里面所需要的参数需要在请求的URL中进行拼接,但是参数太多会导致拼接字符 ...
- SpringCloud学习笔记(3):使用Feign实现声明式服务调用
简介 Feign是一个声明式的Web Service客户端,它简化了Web服务客户端的编写操作,相对于Ribbon+RestTemplate的方式,开发者只需通过简单的接口和注解来调用HTTP API ...
- springCould:使用Feign 实现声明式服务调用
一.Spring Cloud Feign概念引入通过前面的随笔,我们了解如何通过Spring Cloud ribbon进行负责均衡,如何通过Spring Cloud Hystrix进行服务断路保护,两 ...
- SpringCloud(四):使用Feign实现声明式服务调用
一.Feign介绍Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单.使用Feign,只需要创建一个接口并注解.它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解 ...
- spring cloud 入门系列:总结
从我第一次接触Spring Cloud到现在已经有3个多月了,当时是在博客园里面注册了账号,并且看到很多文章都在谈论微服务,因此我就去了解了下,最终决定开始学习Spring Cloud.我在一款阅读A ...
- Spring Cloud Feign声明式服务调用(转载)+遇到的问题
转载:原文 总结: 1.pom添加依赖 2.application中填写正确的eureka配置 3.启动项中增加注解 @EnableFeignClients 4.填写正确的调用接口 通过原文使用Fei ...
- spring cloud 入门系列四:使用Hystrix 实现断路器进行服务容错保护
在微服务中,我们将系统拆分为很多个服务单元,各单元之间通过服务注册和订阅消费的方式进行相互依赖.但是如果有一些服务出现问题了会怎么样? 比如说有三个服务(ABC),A调用B,B调用C.由于网络延迟或C ...
- spring cloud 系列第4篇 —— feign 声明式服务调用 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.feign 简介 在上一个用例中,我们使用ribbon+restTem ...
- Spring Cloud Feign 声明式服务调用
目录 一.Feign是什么? 二.Feign的快速搭建 三.Feign的几种姿态 参数绑定 继承特性 四.其他配置 Ribbon 配置 Hystrix 配置 一.Feign是什么? 通过对前面Sp ...
随机推荐
- Android开发技巧——ViewPager衍生出来的2个类
1.不能左右滑动的ViewPager /* * Date: 14-7-28 * Project: Access-Control-V2 */ package cn.irains.access.v2.co ...
- 【翻译】Sencha Cmd中脚本压缩方法之比较
概述 为什么要修改默认设置 YUI压缩 Google Closure编译器 UglifyJS 案例研究Ext JS 6示例应用程序 注意事项 自定义JS压缩 小结 概述 这么多年来,Web开发人员都被 ...
- IT职场: 选择外企利与弊
前几天有个同学打电话问我选择国内企业与外企的利弊,很可笑的是他是学机械的:既然和我完全不在一个行业,因此我只是说了我们IT外企的利与弊,毕竟隔行如隔山. 首先简单自我介绍一下,我所在的公司是美资500 ...
- 认证模式之Form模式
上面介绍的两种模式都属于HTTP协议规范范畴,由于它的规范使得很多东西无法自定义,例如登录窗口.错误展示页面.所以需要另外一种模式提供更加灵活的认证,也就是基于Form的认证模式. Form模式的认证 ...
- 07_Android操作sqllite数据库(包括2中方式操作数据的方式),单元测试,BaseAdapter的使用,自定义view的综合使用案例
1 目标从sqllite中读取数据并显示如下: MainActivity对应的界面 MainActivity2对应的界面 2 配置Android的清单文件 <?xml ...
- Unity热更新之C#反射动态获取类属性及方法
如果我们要为发布出去的游戏更新一些功能,但又不想让用户重新下载整个游戏包,只让他下载我们更新的资源包,用assetBundle打包资源的方式是可以的,但其中有个最大的例外,那就是脚本. 虽然asset ...
- XBMC源代码分析 2:Addons(皮肤Skin)
前文已经对XBMC源代码的整体架构进行了分析: XBMC源代码分析 1:整体结构以及编译方法 从这篇文章开始,就要对XBMC源代码进行具体分析了.首先先不分析其C++代码,分析一下和其皮肤相关的代码. ...
- MIDlet工作原理
题记 : 现在的J2ME用户已经是日益减少 , 开发也在转型! 无奈之下也不得不写下这系列文章来别了j2me ,也是对过去的一些总结吧! ①: 所有Kjava必须会继承自javax.microedi ...
- 苹果IOS与谷歌 android系统的UI设计原则
一.苹果为IOS的界面设计提出了六大原则: 1.整体美学 整体美学指的是一个应用的表现和行为与它的功能完美集成,传达连贯的信息. 人们关心一个应用是否提供它承诺的功能,但他们也被应用的外观和行为强烈影 ...
- 一张图看懂AR至GL数据流