Spring Cloud feign使用


  • 前言
  • 环境准备
  • 应用模块
  • 应用程序
  • 应用启动
  • feign特性
  • 综上

1. 前言


我们在前一篇文章中讲了一些我使用过的一些http的框架 
服务间通信之Http框架,其实最终还是准备讲述spring cloud fegin,使用spring cloud fegin完成更为优雅的http的调用方式,以及在服务之间的调用与远程调用的注意上,还有一些使用的问题。

2. 环境准备


这回搭建的一个完整的应用不再新建maven工程,改用gradle,spring boot工程推荐的还是使用gradle来构建,并且gradle相对于maven来说优势较多,应用的也越来越广,因此这回尝试一下,使用一回gradle构建spring cloud应用,具体采用的环境、工具等如下:

  • intellij 2016: 编写java程序。

  • jdk8 : 采用java8来编写应用,可以使用java8中一些特性编写更为优雅的代码和运行更为高效的程序。

  • gradle: 用于我们工程的构建、依赖管理、工程打包等等。

3. 应用模块


采用feign来进行服务之间的调用,一般都是需要一个注册中心,这回就采用eureka作为注册中心,以供于两个服务进行服务注册和服务发现,总体服务列别如下:

  • eureka-server: 服务注册中心,用于服务注册和服务发现。

  • service-a: a服务,服务消费者。

  • service-b: b服务,服务提供者。

4. 应用程序


gradle工程中的build.gradle等一些脚本不再展示出来,在这仅仅展示一下工程结构,如下:

.
├── build.gradle
├── eureka-server
│   ├── build.gradle
│   └── src
│   └── main
│   ├── java
│   │   └── cn
│   │   └── com
│   │   └── enreka
│   │   └── EurekaServerApplication.java
│   └── resources
│   └── bootstrap.yml
├── gradlew
├── gradlew.bat
├── service-a
│   ├── build.gradle
│   └── src
│   └── main
│   ├── java
│   │   └── cn
│   │   └── com
│   │   └── devh
│   │   ├── A1ServiceApplication.java
│   │   ├── controllers
│   │   │   └── AServiceController.java
│   │   └── fegin
│   │   └── ServiceBClient.java
│   └── resources
│   ├── application.yml
│   └── bootstrap.yml
├── service-b
│   ├── build.gradle
│   └── src
│   └── main
│   ├── java
│   │   └── cn
│   │   └── com
│   │   └── devh
│   │   ├── B1ServiceApplication.java
│   │   └── controllers
│   │   └── ServiceB1Controller.java
│   └── resources
│   ├── application.yml
│   └── bootstrap.yml
├── settings.gradle
└── zuul
├── build.gradle
└── src
└── main
├── java
│   └── cn
│   └── com
│   └── zuul
│   └── ZuulApplication.java
└── resources

工程结构大致和maven项目中差不多,zuul是api网关模块,这节暂时不讲,留在后期进行讲述。

4.1 eureka-server


eureka server采用的是无中心化的架构,无master/slave区分,每一个server都是对等的,既是Server又是Client,所以其集群方式可以自由发挥,可以各点互连,也可以接力互连采用eureka作为注册中心,在这里一个简单的应用中,我就采用了一个节点当做注册中心,eureka集群可以看看我先前写的这一篇文章Eureka的高可用以及服务提供者、服务消费者集群之间的调用方式,但是eureka作为注册中心也是存在着许多问题的,在随后的文章中进行讲述,同时也讲述zookeeper、etcd、consul和eureka之间的优劣势,话不多说,还是回到eureka server服务上来,单节点的eureka使用还是比较简单的,程序如下:

bootstrap.yml:

server:
port: 8761 spring:
application:
name: eureka-server eureka:
instance:
hostname: localhost
lease-expiration-duration-in-seconds: 30
lease-renewal-interval-in-seconds: 30
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
enable-self-preservation: false

EurekaServerApplication:

package cn.com.enreka;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /**
* Created by xiaxuan on 17/8/27.
*/
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication { public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}

如此,一个简单的eureka就编写完成了,到时直接启动主程序,注册中心就可以正常启动起来。

4.2 服务提供者service-b


service-b是我们的服务提供者,应用比较简单,仅仅是提供一个一个接口以供消费者调用,具体应用程序如下:

配置文件bootstrap.yml:

server:
port: 8070 spring:
application:
name: service-b eureka:
instance:
hostname: localhost
client:
registerWithEureka: true
fetchRegistry: true
serviceUrl:
defaultZone: http://localhost:8761/eureka/

配置文件application.yml:

msg: Hello

配置文件bootstrap.yml和application.yml都可以用来配置参数, 
bootstrap.yml可以理解成系统级别的一些参数配置,这些参数一般是不会变动的。 
application.yml 可以用来定义应用级别的,如果搭配spring-cloud-config使用 application.yml里面定义的文件可以实现动态替换。spring-cloud-config在后期会进行一些讲述,到时再提一下另外一套配置中心,携程的apoll,挺不错。

B1ServiceApplication:

package cn.com.devh;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /**
* Created by xiaxuan on 17/8/26.
*/
@SpringBootApplication
@EnableDiscoveryClient
public class B1ServiceApplication { public static void main(String[] args) {
SpringApplication.run(B1ServiceApplication.class, args);
}
}

和普通的spring boot启动程序没有太多的不同,仅仅只是加了一个@EnableDiscoveryClient注解,便于服务注册和服务发现,同时还可以使用的是另外一个注解,为@EnableEurekaClient,两个的用法基本相同,下次有空讲讲另外一个注解的用途。

提供服务的controller,ServiceB1Controller:

package cn.com.devh.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController; /**
* Created by xiaxuan on 17/8/28.
*/
@RestController
public class ServiceB1Controller { @Autowired
DiscoveryClient discoveryClient; @Value("${msg:unknown}")
private String msg; @RequestMapping(value = "/", method = RequestMethod.GET)
public String printServiceB() {
ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();
return serviceInstance.getServiceId() + " (" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + ")" + "===>Say " + msg;
}
}

提供的接口也比较简单,就是返回当前的serviceId、host、port和一条hello语句。

4.3 服务消费者service-a


service-a是服务消费者,大致和service-b相同,但是还包括feign来调用server-b提供的服务,配置文件不再展示出来,最后会有整体的代码的下载路径,其他具体代码如下:

A1ServiceApplication:

package cn.com.devh;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; /**
* Created by xiaxuan on 17/8/25.
*/
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class A1ServiceApplication { public static void main(String[] args) {
SpringApplication.run(A1ServiceApplication.class, args);
}
}

启动程序与与service-b没有区别,都是加上了一个注解@EnableDiscoveryClient用于服务注册和服务发现使用,然后还单独加上了一个注解@EnableFeignClients,这个注解就是确保feign可以正常使用。

ServiceBClient:

package cn.com.devh.fegin;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; /**
* Created by xiaxuan on 17/8/26.
*/
@FeignClient(name = "service-b")
public interface ServiceBClient { @RequestMapping(value = "/", method = RequestMethod.GET)
String printServiceB();
}

fallback

在service层上实现接口,这里注意value可以用serviceId代替,但是最好用value来指定要调用的服务。

fallback是当程序错误的时候来回调的方法

方法中要用@PathVariable要注解参数

1 @FeignClient(value = "hap-user-admin-service", fallback = OrganizationLabelFeignClientFallback.class)
2 public interface OrganizationLabelFeignClient {
3 @RequestMapping(value = "/v1/organizations/{id}",method = RequestMethod.GET)
4 Organization queryOrgLabel(@PathVariable(name="id") Long id);
5 }

编写程序错误时的回调类,实现接口,在错误时回调

1 @Service
2 public class OrganizationLabelFeignClientFallback implements OrganizationLabelFeignClient {
3 @Override
4 public Organization queryOrgLabel(Long id) {
5 return null;
6 }
7 }

对service-b编写的feignClient,到时用来直接调用service-b提供的服务,而之所以能够正常调用到service-b的服务,就是通过feign中的name字段,会通过注册中心找到对应的服务。

controller,AServiceController:

package cn.com.devh.controllers;

import cn.com.devh.fegin.ServiceBClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; /**
* Created by xiaxuan on 17/8/26.
*/
@RestController
public class AServiceController { @Value("${name:unknown}")
private String name; @Autowired
private ServiceBClient serviceBClient; @Autowired
private DiscoveryClient discoveryClient; @RequestMapping("/")
public String printServiceA() {
ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();
return serviceInstance.getServiceId() + " (" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + ")" + "===>name:" + name + "<br/>" + serviceBClient.printServiceB();
}
}

提供的服务也是比较简单,输出当前服务在注册中心中的serviceId、host、port和使用feign调用service-b的服务。

以上就是我们整个应用中的三个服务,注册中心eureka-server,服务提供者service-b,服务消费者service-a.

5. 应用启动


分别启动三个服务,注册中心eureka-server,服务提供者service-b,服务消费者service-a,在浏览器中输入http://localhost:8761,观察服务状况,如下图:

两个服务都正常启动,现在直接在浏览器中输入http://localhost:8080/,调用service-a提供的接口,结果如下图:

成功输出当前服务在注册中心的信息并且成功调用service-b提供的服务。

6. feign特性


在这个简单的应用中,service-a通过feign调用service-b的服务,并输出service-a和service-b在注册中心中的信息,整个应用编写的还是比较简单,而且feign还有许多其他有意思的特性。

feign不仅有一个name属性,还有一个url属性,如果指定name属性的话,会直接调用在注册中心中注册的本地服务,如果是还指定了url属性的话,就可以直接调用远程的非注册中心的服务,这样在调用其他服务的时候就非常方便,只要url相同,方法签名中的参数相同,就可以成功的调用对方的服务。

同时feign还可以设置断路由,如果服务调用失败的话,可以调用本地写的failback方法,返回一些默认信息或者抛错之类,给了非常灵活的自由度。

另外feign还有重试次数、超时设置、更换底层使用的httpClient框架等等,都非常有意思,有兴趣的可以google看看。

Spring Cloud feign的更多相关文章

  1. 笔记:Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  2. 笔记:Spring Cloud Feign Hystrix 配置

    在 Spring Cloud Feign 中,除了引入了用户客户端负载均衡的 Spring Cloud Ribbon 之外,还引入了服务保护与容错的工具 Hystrix,默认情况下,Spring Cl ...

  3. 笔记:Spring Cloud Feign 其他配置

    请求压缩 Spring Cloud Feign 支持对请求与响应进行GZIP压缩,以减少通信过程中的性能损耗,我们只需要通过下面二个参数设置,就能开启请求与响应的压缩功能,yml配置格式如下: fei ...

  4. 笔记:Spring Cloud Feign 声明式服务调用

    在实际开发中,对于服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以我们通常会针对各个微服务自行封装一些客户端类来包装这些依赖服务的调用,Spring Cloud Feign 在此基础上做了进 ...

  5. 第六章:声明式服务调用:Spring Cloud Feign

    Spring Cloud Feign 是基于 Netflix Feign 实现的,整合了 Spring Cloud Ribbon 和 Spring Cloud Hystrix,除了提供这两者的强大功能 ...

  6. Spring Cloud Feign Ribbon 配置

    由于 Spring Cloud Feign 的客户端负载均衡是通过 Spring Cloud Ribbon 实现的,所以我们可以直接通过配置 Ribbon 的客户端的方式来自定义各个服务客户端调用的参 ...

  7. 微服务架构之spring cloud feign

    在spring cloud ribbon中我们用RestTemplate实现了服务调用,可以看到我们还是需要配置服务名称,调用的方法 等等,其实spring cloud提供了更优雅的服务调用方式,就是 ...

  8. Spring Cloud Feign 在调用接口类上,配置熔断 fallback后,输出异常

    Spring Cloud Feign 在调用接口类上,配置熔断 fallback后,出现请求异常时,会进入熔断处理,但是不会抛出异常信息. 经过以下配置,可以抛出异常: 将原有ErrorEncoder ...

  9. RestTemplate OR Spring Cloud Feign 上传文件

    SpringBoot,通过RestTemplate 或者 Spring Cloud Feign,上传文件(支持多文件上传),服务端接口是MultipartFile接收. 将文件的字节流,放入ByteA ...

随机推荐

  1. ASP.NET Web API 全局权限和异常处理

    转自:http://yangpei.appsp0t.com/post/aglzfnlhbmdwZWlyDAsSBUVudHJ5GLkXDA 正文之前先解决一个问题 Web Api XML序列化的问题 ...

  2. Hadoop专业解决方案-第1章 大数据和Hadoop生态圈

    一.前言: 非常感谢Hadoop专业解决方案群:313702010,兄弟们的大力支持,在此说一声辛苦了,经过两周的努力,已经有啦初步的成果,目前第1章 大数据和Hadoop生态圈小组已经翻译完成,在此 ...

  3. JAVA URI URL 区别

    String urlString = "http://192.168.21.77:8080/swp/mainPage?aa=11&bb%3D22"; URI uri = U ...

  4. PHPExcel导入导出 若在thinkPHP3.2中使用(无论实例还是静态调用(如new classname或classname::function)都必须加反斜杠,因3.2就命名空间,如/classname

    php利用PHPExcel类导出导入Excel用法 来源:   时间:2013-09-05 19:26:56   阅读数: 分享到: 16 [导读] PHPExcel类是php一个excel表格处理插 ...

  5. pip 安装指定版本的python包

    pip install -v package_name==2.3

  6. Python的collections模块中namedtuple结构使用示例

      namedtuple顾名思义,就是名字+元组的数据结构,下面就来看一下Python的collections模块中namedtuple结构使用示例 namedtuple 就是命名的 tuple,比较 ...

  7. 伯克利推出「看视频学动作」的AI智能体

    伯克利曾经提出 DeepMimic框架,让智能体模仿参考动作片段来学习高难度技能.但这些参考片段都是经过动作捕捉合成的高度结构化数据,数据本身的获取需要很高的成本.而近日,他们又更进一步,提出了可以直 ...

  8. 学习MongoDB 六: MongoDB查询(游标操作、游标信息)(三)

    一.简介 db.collection.find()可以实现根据条件查询和指定使用投影运算符返回的字段省略此参数返回匹配文档中的所有字段.并返回到匹配文档的游标,可以随意修改查询限制.跳跃.和排序顺序的 ...

  9. 常用模块:os模块,logging模块等

    一    os模块 那么作为一个常用模块,os模块是与操作系统交互的一个模块. 那么os模块中我们常用的一般有以下几种: os.listdir('dirname') 以列表的形式列出指定目录下的所有文 ...

  10. django的小操作,查询效率up, 引用art-template模板+djangorestframework

    Part1: 提高查询效率newses = News.objects.select_related('category', 'author').get(id=1) # category和author字 ...