笔记:Spring Cloud Feign 声明式服务调用
在实际开发中,对于服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以我们通常会针对各个微服务自行封装一些客户端类来包装这些依赖服务的调用,Spring Cloud Feign 在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,我们只需要创建一个接口并用注解的方式来配置他,即可完成对服务提供方的接口绑定,简化了在使用 Spring Cloud Ribbon 时自行封装服务调用客户端的开发量。
快速入门
- 首先创建一个 Spring Cloud 的基础工程,并增加 spring-cloud-starter-eureka 依赖 和 spring-cloud-starter-feign 依赖,示例代码如下:
<?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>
<groupId>org.lixue</groupId>
<artifactId>eureka-feign-consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>eureka-feign-consumer</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository --></parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</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-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
- 创建应用主类 EurekaFeignConsumerApplication 并通过 @EnableFeignClients 注解开启 Spring Cloud Feign 功能,使用 @EnableDiscoveryClient 注解开启 Eureka的服务发现,代码如下:
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class EurekaFeignConsumerApplication {
public static
void
main(String[] args) {SpringApplication.run(EurekaFeignConsumerApplication.class, args);
}
}
- 定义 HelloWorldService 接口,通过 @FeignClient 注解指定服务名来绑定服务,然后再使用Spring MVC 的注解来绑定具体该服务提供的 REST 接口,代码如下:
@FeignClient ("ORG.LIXUE.HELLOWORLD")
public interface HelloWorldService {
@RequestMapping ("/hi")
String hi();
}
- 在需要调用服务的位置,使用 @Autowired
直接注入
HelloWorldService 实例,并使用该接口实例调用方法 hi 来完成 /hi 接口的调用,示例代码如下:@RestController
public class FeignConsumerController {
@Autowired
HelloWorldService helloWorldService;
@RequestMapping ("/hi")
public String hi() {
return helloWorldService.hi();
}
}
- 在 application.yml 中需要指定服务注册中心,并定义自身的服务名和端口,示例如下:
server:
port: 9200
eureka:
client:
service-url:
defaultZone: http://eurekaserver2:9002/eureka,http://eurekaserver1:9001/eureka
spring:
application:
name: eureka-feign-consumer
- 启动服务注册中心以及二个ORG.LIXUE.HELLOWORLD服务,然后启动 eureka-feign-consumer ,此时发送几次 GET 请求到 http://localhost:9200/hi ,可以正确的返回 Hello World hi 9100 或者 Hello World hi 9101 ,可以看到Feign实现的消费者,依然是利用 Ribbon 维护了针对 ORG.LIXUE.HELLOWORLD服务列表信息,并且通过轮询实现了客户端负载均衡。
参数绑定
在入门示例中我们实现的是一个不带参数的
REST
服务绑定,然而现实系统中的各种业务接口要比他复杂很多,我们会在HTTP的各个位置传入各种不同类型的参数,并且在返回请求响应的时候也可能是一个复杂对象结构,因此我们需要使用
Feign
来对不同形式的参数进行绑定
- @RequestParam 注解:常用来处理简单类型的绑定,通过Request.getParameter() 获取的String可直接转换为简单类型的情况( String--> 简单类型的转换操作由ConversionService配置的转换器来完成);因为使用request.getParameter()方式获取参数,所以可以处理get 方式中queryString的值,也可以处理post方式中 body data的值;用来处理Content-Type: 为 application/x-www-form-urlencoded编码的内容,提交方式GET、POST;该注解有两个属性: value、required; value用来指定要传入值的id名称,required用来指示参数是否必须绑定
@RequestMapping (value = "/hi1", method = RequestMethod.GET)
public String hi(@RequestParam ("name") String name) {
return
"Hello World hi " + port + " name " + name;}
- @CookieValue
注解:可以把Request header中关于cookie的值绑定到方法的参数上@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@CookieValue("JSESSIONID") String cookie) {
//...
}
- @RequestBody 注解:用于读取Request请求的body部分数据,使用系统默认配置的HttpMessageConverter进行解析,然后把相应的数据绑定到要返回的对象上
@RequestMapping (value = "/hi2", method = RequestMethod.POST)
public String hi(@RequestBody User user) {
return
"Hello World hi " + port + "\tUser=" + user;}
注意:User 类必须有默认构造函数
- @RequestHeader 注解:可以把Request请求header部分的值绑定到方法的参数上
@RequestMapping("/displayHeaderInfo.do")
public void displayHeaderInfo(@RequestHeader("Accept-Encoding") String encoding,
@RequestHeader("Keep-Alive") long keepAlive) {
//...
}
- @PathVariable 注解:当使用@RequestMapping URI template 样式映射时, 即 someUrl/{paramId}, 这时的paramId可通过 @Pathvariable
注解绑定它传过来的值到方法的参数上,示例代码如下:@Controller
@RequestMapping("/owners/{ownerId}")
public class RelativePathUriTemplateController {
@RequestMapping("/pets/{petId}")
public void findPet(@PathVariable String ownerId, @PathVariable String petId, Model model) {
// implementation omitted
}
}
继承特性
在Spring
Cloud
Feign 中,提供了继承特性来帮助我们构建相应的服务客户端不安定接口和服务控制器,进一步减少编码量,示例如下:
- 创建一个基础的 Maven 工程,命名为
service-contract,由于需要使用到 Spring MVC 的注解,因此在 pom.xml 中引入 spring-boot-starter-web 依赖,具体内容如下:<?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>
<groupId>org.lixue</groupId>
<artifactId>service-contract</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>service-contract</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.6.RELEASE</version>
<relativePath/>
<!-- lookup parent from repository --></parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Dalston.SR3</spring-cloud.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
</project>
- 在项目中创建服务需要使用的实体类和服务接口,代码如下:
public class User {
private String name;
private
int age;// setter
和
getter
方法@Override
public String toString() {
return
"name=" + name + "\tage=" + age;}
}
@RequestMapping("/hello")
public interface HelloWorldService {
@RequestMapping (value = "/hi", method = RequestMethod.GET)
String hi();
@RequestMapping (value = "/hi1", method = RequestMethod.GET)
String hi(@RequestParam ("name") String name);
@RequestMapping (value = "/hi2", method = RequestMethod.POST)
String hi(@RequestBody User user);
}
- 在服务的具体实现项目中增加 service-contract 的依赖,并且实现服务需要继承上面的 HelloWorldService 接口,并重写接口方法实现具体的服务实现
@RestController
public class HelloWorldController implements HelloWorldService {
@Value ("${server.port}")
int port;
@Override
public String hi() {
return
"hi port " + port;}
@Override
public String hi(String name) {
return
"hi port " + port + " name " + name;}
@Override
public String hi(@RequestBody User user) {
return
"hi port " + port + " user " + user;}
}
- 在具体的消费项目中增加 service-contract 依赖增加接口
HelloWorldServiceProxy ,继承
service-contract 项目中的
HelloWorldService
并使用 @FeignClient 注解来声明调用服务名称@FeignClient ("ORG.LIXUE.HELLOWORLD")
public interface HelloWorldServiceProxy extends HelloWorldService {
}
- 在需要调用服务的位置,使用 @Autowired
直接注入
HelloWorldServiceProxy 实例,并使用该接口实例调用方法 hi 来完成 /hi 接口的调用,示例代码如下:@RestController
public class FeignConsumerController {
@Autowired
HelloWorldService helloWorldService;
@RequestMapping ("/hi")
public String hi() {
User user = new
User();user.setName("liyong");
user.setAge(3434);
StringBuilder stringBuilder = new
StringBuilder();stringBuilder.append("hi=" + helloWorldServiceProxy.hi()).append("<br/>");
stringBuilder.append("hi1=" + helloWorldServiceProxy.hi("lixue")).append("<br/>");
stringBuilder.append("hi2=" + helloWorldServiceProxy.hi(user)).append("<br/>");
return stringBuilder.toString();
}
}
- 在 application.yml 中需要指定服务注册中心,并定义自身的服务名和端口,示例如下:
server:
port: 9200
eureka:
client:
service-url:
defaultZone: http://eurekaserver2:9002/eureka,http://eurekaserver1:9001/eureka
spring:
application:
name: eureka-feign-consumer
- 启动服务注册中心以及二个ORG.LIXUE.HELLOWORLD服务,然后启动 eureka-feign-consumer ,此时发送几次 GET 请求到 http://localhost:9200/hi ,可以正确的返回 Hello World hi 9100 或者 Hello World hi 9101 ,可以看到Feign实现的消费者,依然是利用 Ribbon 维护了针对 ORG.LIXUE.HELLOWORLD服务列表信息,并且通过轮询实现了客户端负载均衡。
笔记:Spring Cloud Feign 声明式服务调用的更多相关文章
- Spring Cloud Feign 声明式服务调用
目录 一.Feign是什么? 二.Feign的快速搭建 三.Feign的几种姿态 参数绑定 继承特性 四.其他配置 Ribbon 配置 Hystrix 配置 一.Feign是什么? 通过对前面Sp ...
- Spring Cloud Feign声明式服务调用(转载)+遇到的问题
转载:原文 总结: 1.pom添加依赖 2.application中填写正确的eureka配置 3.启动项中增加注解 @EnableFeignClients 4.填写正确的调用接口 通过原文使用Fei ...
- Spring Cloud 2-Feign 声明式服务调用(三)
Spring Cloud Feign 1. pom.xml 2. application.yml 3. Application.java 4. Client.java 简化RestTemplate调 ...
- spring cloud 系列第4篇 —— feign 声明式服务调用 (F版本)
源码Gitub地址:https://github.com/heibaiying/spring-samples-for-all 一.feign 简介 在上一个用例中,我们使用ribbon+restTem ...
- Feign声明式服务调用
Feign是一种声明式.模板化的HTTP客户端(仅在Application Client中使用).声明式调用是指,就像调用本地方法一样调用远程方法,无需感知操作远程http请求. Spring Clo ...
- SpringCloud微服务实战二:Spring Cloud Ribbon 负载均衡 + Spring Cloud Feign 声明式调用
1.Spring Cloud Ribbon的作用 Ribbon是Netflix开发的一个负载均衡组件,它在服务体系中起着重要作用,Pivotal将其整合成为Spring Cloud Ribbon,与其 ...
- Spring Cloud07: Feign 声明式接口调用
一.什么是Feign Feign也是去实现负载均衡,但是它的使用要比Ribbon更加简化,它实际上是基于Ribbon进行了封装,让我们可以通过调用接口的方式实现负载均衡.Feign和Ribbon都是由 ...
- SpringCloud实战-Feign声明式服务调用
在前面的文章中可以发现当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率 ...
- Spring Cloud Feign 优雅的服务调用
Fegin 是由NetFlix开发的声明式.模板化HTTP客户端,可用于SpringCloud 的服务调用.提供了一套更优雅.便捷的HTTP调用API,并且SpringCloud整合了Fegin.Eu ...
随机推荐
- redis 突然大量逐出导致读写请求block
现象 redis作为缓存场景使用,内存耗尽时,突然出现大量的逐出,在这个逐出的过程中阻塞正常的读写请求,导致 redis 短时间不可用: 背景 redis 中的LRU是如何实现的? 当mem_used ...
- 利用js实现placeholder占位符,甩开ie不兼容
正常的写法 <input type="text" placeholder="占位符"> 这种写法ie低版本的支持不友好,为了满足某些测试或者产品的变 ...
- 【前端】Vue2全家桶案例《看漫画》之一、添加四个导航页
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/vue_vux_app_1.html 项目github地址:https://github.com/shamoyuu/ ...
- Hi3531 SDK v2.0.8.0 安装
1.Hi3531 SDK包位置 在"Hi3531_V100R001***/01.software/board"目录下,您可以看到一个 Hi3531_SDK_Vx.x.x.x.tgz ...
- MySQL插入数据异常
MySQL插入数据异常 1.错误如下: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:Dupli ...
- directX--关于CSource和CSourceStream (谁调用了fillbuffer)
CSourceStream类,是CSource类的OutputPin[source.h/source.cpp]派生自CAMThread和CBaseOutputPinl 成员变量: CS ...
- javaWeb之自动发送邮件生日祝福(ServletContextListener监听)
在看完本随笔仍然不理解的可以看 javaWeb邮箱发送 :里面有具体的邮箱服务器配置 企业在员工生日当天发送邮箱生日祝福: 一般是用监听器完成: 而合适的监听是ServletContextLis ...
- HTML5结合CSS的三种方法+结合JS的三种方法
HTML5+CSS: HTML中应用CSS的三种方法 一.内联 内联样式通过style属性直接套进HTML中去. 示例代码 <pstylepstyle="color:red" ...
- jquery自带的方法
5.1,$.trim $.trim(" Hello, chinaren_1123 & 摆渡浮桥! "); //去掉前后空格后->Hello, chinaren ...
- PyTorch官方中文文档:自动求导机制
自动求导机制 本说明将概述Autograd如何工作并记录操作.了解这些并不是绝对必要的,但我们建议您熟悉它,因为它将帮助您编写更高效,更简洁的程序,并可帮助您进行调试. 从后向中排除子图 每个变量都有 ...