Spring Cloud 声明式服务调用 Feign
一、简介
在上一篇中,我们介绍注册中心Eureka,但是没有服务注册和服务调用,服务注册和服务调用本来应该在上一章就应该给出例子的,但是我觉得还是和Feign一起讲比较好,因为在实际项目中,都是使用声明式调用服务。而不会在客服端和服务端存储2份相同的model和api定义。Feign在RestTemplate的基础上对其封装,由它来帮助我们定义和实现依赖服务接口的定义。Spring Cloud Feign 基于Netflix Feign 实现的,整理Spring Cloud Ribbon 与 Spring Cloud Hystrix,并且实现了声明式的Web服务客户端定义方式。
二、实践
在上一节中,我继续添加工程模块,最后的模块如下:

首先我们需要建一个工程,名为hello-service-api 在工程主要定义对外提供的model 和api。服务的提供方和服务的消费方都要依赖该工程jar,这样我们就可以只维护一份model 和api定义。在该例子中主要如下结构

非常简单,只有1个HelloServieRemoteApi 接口定义和User对象。
@RequestMapping("/hello-service-remote")
public interface HelloServiceRemoteApi {
@RequestMapping(value = "/hello1", method = RequestMethod.GET)
String hello(@RequestParam("name") String name);
@RequestMapping(value = "/hello2", method = RequestMethod.GET)
User hello(@RequestHeader("name") String name,@RequestHeader("age") Integer age);
@RequestMapping(value = "/hello3", method = RequestMethod.POST)
String hello(@RequestBody User user);
}
在上面的接口定义中,我们非常的清晰,在接口上面我们主映射为/hello-service-remote,个人感觉已接口的名字通过“-”这样可以非常的区分不同的接口路径,防止多接口时发生重复。接下来具体方法的上面可以定义于方法名一样的路径映射,我这里已 /hello1,/hello2,/hello3为主。
public class User implements Serializable {
private static final long serialVersionUID = -7233238826463139634L;
private Long id;
private String name;
private Integer age;
public User() {
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
上面就是简单的一个User对象。
从上面的接口中发现,该api工程需要引入spring-web包。所以它的pom.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<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> <artifactId>hello-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
<groupId>com.qee.hello</groupId> <dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.2.9.RELEASE</version>
</dependency>
</dependencies>
</project>
从上面的pom.xml定义中,我们知道hello-service-api并不集成父工程micro-service-integration。一般作为api提供的工程jar,依赖越少越好。
接下来我们需要创建一个提供者工程,我们把它命名为hello-service-compose。该工程也是标准的Spring Boot工程。具体的目录如下:

在工程中我们有一个刚才hello-service-api接口定义的实现。代码如下:
@RestController
public class HelloServiceRemoteApiImpl implements HelloServiceRemoteApi { @Override
public String hello(@RequestParam("name") String name) {
return "hello " + name;
} @Override
public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
try {
name= URLDecoder.decode(name,"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return new User(name, age);
} @Override
public String hello(@RequestBody User user) {
if (user == null) {
return "未知";
}
return user.toString();
}
}
因为是测试工程,所以它没有复杂的业务逻辑。接下来就是HelloProviderApplication的启动main.
package com.qee.remote; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; @EnableDiscoveryClient
@SpringBootApplication
public class HelloProviderApplication { public static void main(String[] args) {
SpringApplication.run(HelloProviderApplication.class, args);
}
}
在上面有2个注解,第一个 SpringBootApplication 就是Spring Boot 启动注解,EnableDiscoveryClient 该注解会把RestController修饰的类注册到注册中心去。
接下来我们来看下application.properties
server.port=8885 spring.application.name=hello-service-compose eureka.instance.hostname=register.center.com eureka.instance.server.port=8881 #默认的注册域
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/ #控制台彩色输出
spring.output.ansi.enabled=ALWAYS
从上面信息我们知道,改工程启动端口为8885,注册中心地址为register.center.com:8881。
接下来我们查看一下该工程的pom.xml定义
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>micro-service-integration</artifactId>
<groupId>spring.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion> <artifactId>hello-service-compose</artifactId> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties> <dependencies>
<dependency>
<groupId>com.qee.hello</groupId>
<artifactId>hello-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependencies>
</project>
从pom.xml文件中知道该工程依赖了web,euraka,ribbon,actuator,hello-service-api 包。其中euraka为服务注册和发现包,ribbon为服务调用负载均衡包,actuator为工程元信息检测包。还有我们自己定义的hello-service-api包。
在上面的简单配置和编写后,我们就可以启动工程把该HelloServiceRemoteApi注册到注册中心去了。
现在有了服务接口定义包和服务提供工程,现在我们编写一下服务调用工程。命名为hello-service-web。该工程的目录结构如下:

首先我们来看下HelloBackgroundService 这个接口。
@FeignClient(value = "hello-service-compose")
public interface HelloBackgroundService extends HelloServiceRemoteApi{
}
非常的简单,主要继承我们之前编辑的HelloServiceRemoteApi,并且在上面打上FeignClient注解,该注解指定服务名来绑定服务。该注解同时会使服务调用具有负载均衡的能力。
接下来我们来看下HelloController类
@RestController
public class HelloController { @Autowired
private HelloBackgroundService helloBackgroundService; @RequestMapping("/hello")
public Map<String,Object> hello(){
Map<String,Object> ret = new HashMap<String, Object>();
StringBuffer sb = new StringBuffer();
String s1 = helloBackgroundService.hello("张三");
sb.append(s1).append("\n");
User user = null;
try {
user = helloBackgroundService.hello(URLEncoder.encode("李四", "UTF-8"), 30);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
sb.append(user.toString()).append("\n");
String s3 = helloBackgroundService.hello(new User("王五", 19));
sb.append(s3).append("\n");
ret.put("show",sb.toString());
return ret;
}
}
从上面得知我们,我们就可以调用之前的我们编写的HelloBackgroundService了。接下来我们查看一下启动类HelloConsumerApp
package com.qee; import feign.Logger;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean; @EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class HelloConsumerApp { @Bean
Logger.Level feginLoggerLevel(){
return Logger.Level.FULL;
} public static void main(String[] args) {
SpringApplication.run(HelloConsumerApp.class, args);
}
}
在该启动了中又多了一个注解EnableFeignClients ,该注解开启Spring Cloud Feign的支持。接着我们来查看一下application.properties
server.port=8887 spring.application.name=hello-service-web eureka.instance.hostname=register.center.com eureka.instance.server.port=8881 #默认的注册域
eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/ #开启请求压缩功能
feign.compression.request.enabled=true #开启响应压缩功能
feign.compression.response.enabled=true #指定压缩请求数据类型
feign.compression.request.mime-types=text/xml;application/xml;application/json #如果传输超过该字节,就对其进行压缩
feign.compression.request.min-request-size=2048 #控制台彩色输出
spring.output.ansi.enabled=ALWAYS #日志配置,该接口的日志级别
logging.level.com.qee.service.HelloBackgroundService=DEBUG
从上面的注释中,我们已经可以知道具体的配置参数的作用,这里就不详细介绍了。从上面的配置和编写我们可以知道,该工程需要如下的依赖包,pom.xml文件如下
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>micro-service-integration</artifactId>
<groupId>spring.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion> <artifactId>hello-service-web</artifactId> <properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties> <dependencies>
<dependency>
<groupId>com.qee.hello</groupId>
<artifactId>hello-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency> <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency> </dependencies>
</project>
该服务消费端,比服务提供方多了一个jar依赖,就是feign。该jar的作用就是提供声明式的服务调用。到这里我们本章的内容大致结束,最后我们来运行这几个工程。查看如下结果:

从上面我们可以看到2个工程hello-service-compose 和hello-service-web都已经注册到注册中心eureka上了。接下来看一下调用结果:

到这里服务注册中心启动,服务注册,服务消费大致都已完成,之后会向大家一起学习服务调用的负载均衡Ribbon和服务容错保护Hystrix.
Spring Cloud 声明式服务调用 Feign的更多相关文章
- SpringCloud 源码系列(6)—— 声明式服务调用 Feign
SpringCloud 源码系列(1)-- 注册中心 Eureka(上) SpringCloud 源码系列(2)-- 注册中心 Eureka(中) SpringCloud 源码系列(3)-- 注册中心 ...
- SpringCloud之声明式服务调用 Feign(三)
一 Feign简介 Feign是一种声明式.模板化的HTTP客户端,也是netflix公司组件.使用feign可以在远程调用另外服务的API,如果调用本地API一样.我们知道,阿里巴巴的doubbo采 ...
- SpringCloud开发学习总结(七)—— 声明式服务调用Feign(一)
在实践的过程中,我们会发现在微服务架构中实现客户端负载均衡的服务调用技术Spring Cloud Ribbon<SpringCloud开发学习总结(四)—— 客户端负载均衡Ribbon> ...
- 004声明式服务调用Feign & 断路器Hystrix
1.POM配置 和普通Spring Boot工程相比,添加了Eureka Client.Feign.Hystrix依赖和Spring Cloud依赖管理 <dependencies> &l ...
- spring cloud 声明式rest客户端feign调用远程http服务
在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.Feign就是Spring Cloud提供的一种声明式R ...
- Spring Cloud Feign 1(声明式服务调用Feign 简介)
Spring Cloud Feign基于Netflix Feign 同时整合了Spring Cloud Ribbon和Spring Cloud Hytrix,除了提供两者的强大功能外,它还提供了一种声 ...
- Spring Cloud第七篇 | 声明式服务调用Feign
本文是Spring Cloud专栏的第七篇文章,了解前六篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cloud ...
- 【Dalston】【第三章】声明式服务调用(Feign)
当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻.那 ...
- 声明式服务调用Feign
什么是 Feign Feign 是种声明式.模板化的 HTTP 客户端(仅在 consumer 中使用). 什么是声明式,有什么作用,解决什么问题? 声明式调用就像调用本地方法一样调用远程方法;无 ...
随机推荐
- Asp.NetCore之组件写法
本章内容和大家分享的是Asp.NetCore组件写法,在netcore中很多东西都以提供组件的方式来使用,比如MVC架构,Session,Cache,数据库引用等: 这里我也通过调用验证码接口来自定义 ...
- MyBetis3.2框架技术
1.1 MyBatis介绍 MyBatis 世界上流行最广泛的基于SQ语句的ORM框架,由Clinton Begin 在2002 年创建,其后,捐献给了Apache基金会,成立了iBatis 项 ...
- 20155304 实验一《Java开发环境的熟悉》实验报告
20155304 实验一实验报告 实验一 Java开发环境的熟悉 实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用IDEA编译.编译.运行.调试Java程序. 实验步骤 (一)命令行下 ...
- Python学习_ConfigParse (转)
1.基本的读取配置文件 -read(filename) 直接读取ini文件内容 -sections() 得到所有的section,并以列表的形式返回 -options(section) 得到该se ...
- onclick = xxx这种赋值写法绑定事件的原理是什么?
本文转自知乎貘吃馍香的回答 提问:刚入门不久,能力有限,这个问题我描述起来有点困难,只有劳烦各位大神细看了 我之前一直以为js底层存在类似下面这样的代码: //给所有dom对象定义好onclick值为 ...
- 线段树(hdu 1754 i hate it)
I Hate It Time Limit: 3000MS Memory Limit: 32768 K Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分 ...
- StringBuilder的实现
先看看MS给出的官方解释吧 (http://msdn.microsoft.com/zh-cn/library/system.text.stringbuilder(VS.80).aspx) String ...
- App内切换语言
前几天客户提需求,对App增加一个功能,这个功能目前市面上已经很常见,那就是应用内切换语言.啥意思,就是 英.中.法.德.日...语言随意切换. (本案例采用Data-Bingding模式,麻麻再也不 ...
- STM32之呼吸灯实验
首先,我想引用一下在一片博文里 看到 的一段话,写的很详细, 首先来说,你要使用PWM模式你得先选择用那个定时器来输出PWM吧!除了TIM6.TIM7这两个普通的定时器无法输出PWM外,其余的定时器都 ...
- Linux 上搭建 git 的服务器
搭建服务器 假设服务器的名字是 git.example.com. 首先,添加一个叫做git的用户adduser git. 然后如果不存在的话, 为这个用户新建一个主目录mkdir /home/git, ...