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
并且多次访问的话,会轮询调用两个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 ...
随机推荐
- SQL Sever2005卸载问题解决措施
在安装SQLServer 2005时,曾遇到过SQL database service不能安装类似问题,曾经花费3个小时时间,最终将其安装成功.将其大概纠错过程记录如下,以作为前车之鉴. ...
- Cocos2D:塔防游戏制作之旅(十五)
Yes,貌似添加了好多的代码啊 ;] ,在你添加更多代码时,你可能注意到一些Xcode中的一些警告.首先你先忽略这些警告,我们先添加少量最终缺失的部分,然后再来解释上面代码做了什么! 在Enemy.m ...
- Mybatis接口编程原理分析(三)
前面两篇博客Mybatis接口编程原理分析(一)和Mybatis接口编程原理分析(二)我们介绍了MapperProxyFactory.MapperProxy和MapperMethod的操作及源码分析, ...
- Spring Security3 - MVC 整合教程
下面我们将实现关于Spring Security3的一系列教程. 最终的目标是整合Spring Security + Spring3MVC 完成类似于SpringSide3中mini-web的功能 ...
- leetcode之 Palindrome Partitioning I&II
1 Palindrome Partitioning 问题来源:Palindrome Partitioning 该问题简单来说就是给定一个字符串,将字符串分成多个部分,满足每一部分都是回文串,请输出所有 ...
- spring4泛型初探----一个小例子
泛型的出现,是为了让代码更规整. 例如 Set<String> set=new HashSet<>(); set.add("abc"); set.add(1 ...
- (NO.00002)iOS游戏精灵战争雏形(五)
完成了精灵自己移动之后,我们开始着手实现按住精灵拖动的功能. 要想处理触摸事件,我们需要做2件事: 1.在类的初始化中打开触摸接收属性 2.实现触摸处理回调方法 我们依次来做这2件事. 首先要搞清楚在 ...
- 《java入门第一季》之面向对象(内部类到底在哪里?)
/* 内部类概述: 把类定义在其他类的内部,这个类就被称为内部类. 举例:在类A中定义了一个类B,类B就是内部类. 内部的访问特点: A:内部类可以直接访问外部类的成员,包括私有. B:外部类要访问内 ...
- 学习OpenCV,GPU模块
如何使用opencv的gpu库呢?我这两天一直在搞这个事情,环境的配置见上文(转载),这里我先举个简单的例子,实现这样的功能:host读入一幅图像,加载到GPU上,在GPU上复制一份然后下传到host ...
- mysql进阶(十八)完全卸载mysql数据库图文教程
完全卸载mysql数据库图文教程 有时候MySQL不能完全卸载,这时候必须通过一些途径删除掉注册表和一些残余的文件,然后才能重新安装才可以成功! 方法/步骤 1.控制面板-->所有控制面板项-- ...