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 ...
随机推荐
- 【一天一道LeetCode】#82. Remove Duplicates from Sorted List II
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given a ...
- Java实现二叉树的创建和遍历操作(有更新)
博主强烈建议跳过分割线前面的部分,直接看下文更新的那些即可. 最近在学习二叉树的相关知识,一开始真的是毫无头绪.本来学的是C++二叉树,但苦于编译器老是出故障,于是就转用Java来实现二叉树的操作.但 ...
- Chapter 3 Protecting the Data(1):理解权限
原文出处:http://blog.csdn.net/dba_huangzj/article/details/39548665,专题目录:http://blog.csdn.net/dba_huangzj ...
- awk 循环语句例子
awk 循环语句例子 运行结果:
- outlook邮箱邮件与企业邮箱同步(outlook本地文件夹邮件,web邮箱里没有)
用惯了outlook2010, 问题:今天将邮件放到自定义文件夹后,发现在web邮箱中看不到邮件了.不能同步到企业邮箱. 解决忙了一天,才知道是账户类型问题,pop3类型,只下载不上传.所以outlo ...
- Java实现栈之计算器
Java实现栈来做一个将中缀表达式转化为后缀表达式的程序,中缀表达式更符合我们的主观感受,后缀表达式更适合计算机的运算,下面直接上代码吧: package Character1; import jav ...
- Python学习笔记 - ifelifelse-forin-while
if elif else #!/usr/bin/env python3 # -*- coding: utf-8 -*- age = 20 if age >= 18: print('your ag ...
- (五十六)iOS多线程之NSOperation
NSOpertation是一套OC的API,是对GCD进行的Cocoa抽象. NSOperation有两种不同类型的队列,主队列和自定义队列. 主队列运行于主线程上,自定义队列在后台运行. [NSBl ...
- (NO.00001)iOS游戏SpeedBoy Lite成形记(二十)
下面修改最为关键的matchRun方法里的代码: CCActionCallBlock *blk = [CCActionCallBlock actionWithBlock:^{ _finishedCou ...
- JavaScript进阶(七)JS截取字符串substr 和 substring方法的区别
JS截取字符串substr 和 substring方法的区别 substr方法 返回一个从指定位置开始的指定长度的子字符串. stringvar.substr(start [, length ]) 参 ...