springcloud入门教程:用声明式rest客户端feign调用远端http服务

大象O无形      2022-02-14     141

关键词:

首先简单解释一下什么是声明式实现?

要做一件事, 需要知道三个要素,where, what, how。即在哪里( where)用什么办法(how)做什么(what)。什么时候做(when)我们纳入how的范畴。

1)编程式实现: 每一个要素(where,what,how)都需要用具体代码实现来表示。传统的方式一般都是编程式实现,业务开发者需要关心每一处逻辑

2)声明式实现: 只需要声明在哪里(where )做什么(what),而无需关心如何实现(how)。Spring的AOP就是一种声明式实现,比如网站检查是否登录,开发页面逻辑的时候,只需要通过AOP配置声明加载页面(where)需要做检查用户是否登录(what),而无需关心如何检查用户是否登录(how)。如何检查这个逻辑由AOP机制去实现, 而AOP的登录检查实现机制与正在开发页面的逻辑本身是无关的。

在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端。Feign就是Spring Cloud提供的一种声明式REST客户端。可以通过Feign访问调用远端微服务提供的REST接口。现在我们就用Feign来调用SERVICE-HELLOWORLD暴露的REST接口,以获取到“Hello World”信息。在使用Feign时,Spring Cloud集成了Ribbon和Eureka来提供HTTP客户端的负载均衡。

下面我们就采用Feign的方式来调用Hello World服务集群。

1. 创建Maven工程,加入spring-cloud-starter-feign依赖

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-feign</artifactId>
        </dependency>

完整的pom文件如下:

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" 
 3         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 4         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5     <modelVersion>4.0.0</modelVersion>
 6     <groupId>com.chry</groupId>
 7     <artifactId>springcloud.helloworld.feign.client</artifactId>
 8     <version>0.0.1-SNAPSHOT</version>
 9     <packaging>jar</packaging>
10     <name>springcloud.helloworld.feign.client</name>
11     <description>Demo Feigh client application</description>
12 
13     <parent>
14         <groupId>org.springframework.boot</groupId>
15         <artifactId>spring-boot-starter-parent</artifactId>
16         <version>1.5.3.RELEASE</version>
17         <relativePath/> <!-- lookup parent from repository -->
18     </parent>
19 
20     <properties>
21         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
22         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
23         <java.version>1.8</java.version>
24     </properties>
25 
26     <dependencies>
27         <dependency>
28             <groupId>org.springframework.cloud</groupId>
29             <artifactId>spring-cloud-starter-eureka</artifactId>
30         </dependency>
31         <dependency>
32             <groupId>org.springframework.cloud</groupId>
33             <artifactId>spring-cloud-starter-feign</artifactId>
34         </dependency>
35         <dependency>
36             <groupId>org.springframework.boot</groupId>
37             <artifactId>spring-boot-starter-web</artifactId>
38         </dependency>
39 
40         <dependency>
41             <groupId>org.springframework.boot</groupId>
42             <artifactId>spring-boot-starter-test</artifactId>
43             <scope>test</scope>
44         </dependency>
45     </dependencies>
46 
47     <dependencyManagement>
48         <dependencies>
49             <dependency>
50                 <groupId>org.springframework.cloud</groupId>
51                 <artifactId>spring-cloud-dependencies</artifactId>
52                 <version>Dalston.RC1</version>
53                 <type>pom</type>
54                 <scope>import</scope>
55             </dependency>
56         </dependencies>
57     </dependencyManagement>
58 
59     <build>
60         <plugins>
61             <plugin>
62                 <groupId>org.springframework.boot</groupId>
63                 <artifactId>spring-boot-maven-plugin</artifactId>
64             </plugin>
65         </plugins>
66     </build>
67 
68     <repositories>
69         <repository>
70             <id>spring-milestones</id>
71             <name>Spring Milestones</name>
72             <url>https://repo.spring.io/milestone</url>
73             <snapshots>
74                 <enabled>false</enabled>
75             </snapshots>
76         </repository>
77     </repositories>
78 </project>
pom.xml

2. 创建启动类,需呀加上@EnableFeignClients注解以使用Feign, 使用@EnableDiscoveryClient开启服务自动发现

 1 package springcloud.helloworld.feign.service;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 6 import org.springframework.cloud.netflix.feign.EnableFeignClients;
 7 
 8 @SpringBootApplication
 9 @EnableDiscoveryClient
10 @EnableFeignClients
11 public class ServiceFeignApplication {
12     public static void main(String[] args) {
13         SpringApplication.run(ServiceFeignApplication.class, args);
14     }
15 }

3. 添加配置文件application.yml, 使用端口8902, 名字定义为service-feign, 并注册到eureka服务中心

1 eureka:
2    client:
3       serviceUrl:
4         defaultZone: http://localhost:8761/eureka/
5 server:
6    port: 8902
7 spring:
8    application:
9       name: service-feign

4. 定义Feign:一个用@FeignClient注解的接口类,

@FeignClient用于通知Feign组件对该接口进行代理(不需要编写接口实现),使用者可直接通过@Autowired注入; 该接口通过value定义了需要调用的SERVICE-HELLOWORLD服务(通过服务中心自动发现机制会定位具体URL); @RequestMapping定义了Feign需要访问的SERVICE-HELLOWORLD服务的URL(本例中为根“/”)

 1 package springcloud.helloworld.feign.service;
 2 
 3 import org.springframework.cloud.netflix.feign.FeignClient;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 import org.springframework.web.bind.annotation.RequestMethod;
 6 
 7 @FeignClient(value = "SERVICE-HELLOWORLD")
 8 public interface HelloWorldService {
 9     @RequestMapping(value = "/",method = RequestMethod.GET)
10     String sayHello();
11 }

Spring Cloud应用在启动时,Feign会扫描标有@FeignClient注解的接口,生成代理,并注册到Spring容器中。生成代理时Feign会为每个接口方法创建一个RequetTemplate对象,该对象封装了HTTP请求需要的全部信息,请求参数名、请求方法等信息都是在这个过程中确定的,Feign的模板化就体现在这里

5. 定义一个WebController。

注入之前通过@FeignClient定义生成的bean, 

sayHello()映射到http://localhost:8902/hello, 在这里,我修改了Hello World服务的映射,将根“/”, 修改成了“/hello”。

 1 package springcloud.helloworld.feign.service;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.web.bind.annotation.RequestMapping;
 5 import org.springframework.web.bind.annotation.RequestMethod;
 6 import org.springframework.web.bind.annotation.RestController;
 7 
 8 @RestController
 9 public class WebController {
10     @Autowired HelloWorldService helloWorldFeignService;
11     @RequestMapping(value = "/hello",method = RequestMethod.GET)
12     public String sayHello(){
13         return helloWorldFeignService.sayHello();
14     }
15 }

6. 启动Feign应用, 访问http://localhost:8902/hello, 多次刷新,可以看到和前一章Ribbon里面的应用一样, 两个Hello World服务的输出交替出现。说明通过Feign访问服务, Spring Cloud已经缺省使用了Ribbon负载均衡。

                

6. 在Feign中使用Apache HTTP Client

Feign在默认情况下使用的是JDK原生的URLConnection发送HTTP请求,没有连接池,但是对每个地址gwai会保持一个长连接,即利用HTTP的persistence connection 。我们可以用Apache的HTTP Client替换Feign原始的http client, 从而获取连接池、超时时间等与性能息息相关的控制能力。Spring Cloud从Brixtion.SR5版本开始支持这种替换,首先在项目中声明Apache HTTP Client和feign-httpclient依赖:

 1 <!-- 使用Apache HttpClient替换Feign原生httpclient -->
 2         <dependency>
 3             <groupId>org.apache.httpcomponents</groupId>
 4             <artifactId>httpclient</artifactId>
 5         </dependency>
 6         <dependency>
 7             <groupId>com.netflix.feign</groupId>
 8             <artifactId>feign-httpclient</artifactId>
 9             <version>${feign-httpclient}</version>
10         </dependency>
然后在application.properties中添加:
feign.httpclient.enabled=true

 7. Feign的Encoder、Decoder和ErrorDecoder

Feign将方法签名中方法参数对象序列化为请求参数放到HTTP请求中的过程,是由编码器(Encoder)完成的。同理,将HTTP响应数据反序列化为Java对象是由解码器(Decoder)完成的。默认情况下,Feign会将标有@RequestParam注解的参数转换成字符串添加到URL中,将没有注解的参数通过Jackson转换成json放到请求体中。注意,如果在@RequetMapping中的method将请求方式指定为POST,那么所有未标注解的参数将会被忽略,例如:

@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET)
void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName, DataObject obj);

此时因为声明的是GET请求没有请求体,所以obj参数就会被忽略。

在Spring Cloud环境下,Feign的Encoder只会用来编码没有添加注解的参数。如果你自定义了Encoder, 那么只有在编码obj参数时才会调用你的Encoder。对于Decoder, 默认会委托给SpringMVC中的MappingJackson2HttpMessageConverter类进行解码。只有当状态码不在200 ~ 300之间时ErrorDecoder才会被调用。ErrorDecoder的作用是可以根据HTTP响应信息返回一个异常,该异常可以在调用Feign接口的地方被捕获到。我们目前就通过ErrorDecoder来使Feign接口抛出业务异常以供调用者处理。

以上6~7完全摘自 http://blog.csdn.net/neosmith/article/details/52449921

上一篇:Spring Cloud 入门教程(五): Ribbon实现客户端的负载均衡

下一篇:Spring Cloud 入门教程(七): 断路器

参考资料: http://blog.csdn.net/neosmith/article/details/52449921

                   http://blog.csdn.net/forezp/article/details/69808079

                   http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign

springcloud(10)——声明式的rest客户端feign(代码片段)

声明式的Rest客户端Feign是一个声明式的Rest客户端,它可以跟SpringMVC的相关注解一起使用,也可以使用SpringWeb的HttpMessageConverter进行请求或响应内容的编解码。其底层使用的Ribbon和Eureka,从而拥有客户端负载均衡的功能。使用它需... 查看详情

springcloud:使用feign实现声明式rest调用

一、简介前面我们是使用RestTemplate实现restapi调用的,代码如下:@GetMapping("/user/{id}")public User findById(@PathVariable Long id) throws Exception {    return & 查看详情

springcloud(10):使用feign实现声明式rest调用-构造多参数请求

请求多参数的URL假设请求的URL包含多个参数,如:http://localhost:8086/user1?id=1&username=nihao 1.1、Feign接口@FeignClient(name = "spring-ribbon-eureka-client2")public interface UserFeignClient&nb 查看详情

18.springcloud实战项目-整合openfeign实现声明式远程调用

SpringCloud实战项目全套学习教程连载中PassJava学习教程简介PassJava-Learning项目是PassJava(佳必过)项目的学习教程。对架构、业务、技术要点进行讲解。PassJava是一款Java面试刷题的开源系统,可以用零碎时间利用小程序查看常见面... 查看详情

springcloud声明式服务调用:feign

Feign介绍Feign是一个声明式的REST客户端,它用了基于接口的注解方式,可以很方便地实现客户端配置。Feign最初由Netflix公司提供,但最初不支持SpringMVC注解,后由SpringCloud对其封装,才支持了SpringMVC注解,让使用者更易于接受 查看详情

springcloud学习-feign入门

feign 是一个让rest服务调用更简洁的开源项目,很多介绍文章或书也称它为声明式REST调用。传统的webservice中,通过引用wsdl来自动生成一些client的代理类(或stub代码),feign跟这个有点类似,但是更灵活。先回顾一下,上节中... 查看详情

springcloud——feign声明式服务调用(代码片段)

什么是FeignFeign是SpringCloudNetflix组件中的一个轻量级RESTFUL和HTTP服务客户端,实现了负载均衡和Rest调用的开源框架,封装了Ribbon和RestTemplate,实现了webService的面向接口编程,进一步降低了项目的耦合度。是一种声... 查看详情

springcloud——feign声明式服务调用(代码片段)

什么是FeignFeign是SpringCloudNetflix组件中的一个轻量级RESTFUL和HTTP服务客户端,实现了负载均衡和Rest调用的开源框架,封装了Ribbon和RestTemplate,实现了webService的面向接口编程,进一步降低了项目的耦合度。是一种声... 查看详情

springcloud无废话入门03:feign声明式服务调用

1.Feign概述     在上一篇的HelloService这个类中,我们有这样一行代码:     returnrestTemplate.getForObject("http://hello-service/hello",String.class);     查看详情

springcloud——feign声明式服务调用(代码片段)

什么是FeignFeign是SpringCloudNetflix组件中的一个轻量级RESTFUL和HTTP服务客户端,实现了负载均衡和Rest调用的开源框架,封装了Ribbon和RestTemplate,实现了webService的面向接口编程,进一步降低了项目的耦合度。是一种声... 查看详情

springcloudfeign调用过程分析

前面已经学习了两个SpringCloud组件:Eureka:实现服务注册功能;Ribbon:提供基于RestTemplate的HTTP客户端并且支持服务负载均衡功能。通过这两个组件我们暂时可以完成服务注册和可配置负载均衡的服务调用。今天我们要学习的是Fei... 查看详情

springcloud第七篇|声明式服务调用feign

本文是SpringCloud专栏的第七篇文章,了解前六篇文章内容有助于更好的理解本文:SpringCloud第一篇|SpringCloud前言及其常用组件介绍概览SpringCloud第二篇|使用并认识Eureka注册中心SpringCloud第三篇|搭建高可用Eureka注册中心SpringCloud第四... 查看详情

springcloud:服务调用-声明式客户端访问

环境springcloudEdgware.SR6jdk7sts4.6.0mysql5.7背景通过声明式客户端openfeign进行支付微服务的访问。搭建步骤只需要修改支付服务调用层,增加依赖就可以了。支付服务调用层只需要定义接口,不需要进行实现。packagejiangbo.springcloud.dao;im... 查看详情

springcloudopenfeign文档

SpringCloudOpenFeign声明式REST客户端:FeignFeign是一个声明式网络服务客户端, 它使得书写网络服务器更加简单。通过使用Feign创建一个接口并且对他进行声明。具有可插拔声明支持,包括feign声明和JAX-RS声明。Feign同样支持可插拔... 查看详情

使用feign实现声明式rest调用(代码片段)

使用Feign实现声明式REST调用之前示例中是使用RestTemplate实现RESTAPI调用的,代码大致如下: publicUserfindById(@PathVariableLongid)returnthis.restTemplate.getForObject("http://microservice-provider-user/"&# 查看详情

企业级springcloud教程服务消费者(rest+ribbon)

...一个独立的服务,服务与服务的通讯是基于httprestful的。Springcloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。在这一篇文章首先讲解下基于ribbon+rest。一、ribbon简介Ribbonisaclientsideloadbalancerwhichgivesyoua 查看详情

企业级springcloud服务消费者(rest+ribbon)

一、ribbon简介RibbonisaclientsideloadbalancerwhichgivesyoualotofcontroloverthebehaviourofHTTPandTCPclients.FeignalreadyusesRibbon,soifyouareusing@FeignClientthenthissectionalsoapplies.—–摘自官网ribbon是一个负载均衡客 查看详情

springcloud教程|第二篇:服务消费者(rest+ribbon)(finchley版本)

...一个独立的服务,服务与服务的通讯是基于httprestful的。Springcloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。在这一篇文章首先讲解下基于ribbon+rest。一、ribbon简介Ribbonisaclientsideloadbalancerwhichgivesyoua 查看详情