一、简介

在上一篇中,我们介绍注册中心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对象。

  1. @RequestMapping("/hello-service-remote")
  2. public interface HelloServiceRemoteApi {
  3.  
  4. @RequestMapping(value = "/hello1", method = RequestMethod.GET)
  5. String hello(@RequestParam("name") String name);
  6.  
  7. @RequestMapping(value = "/hello2", method = RequestMethod.GET)
  8. User hello(@RequestHeader("name") String name,@RequestHeader("age") Integer age);
  9.  
  10. @RequestMapping(value = "/hello3", method = RequestMethod.POST)
  11. String hello(@RequestBody User user);
  12.  
  13. }

在上面的接口定义中,我们非常的清晰,在接口上面我们主映射为/hello-service-remote,个人感觉已接口的名字通过“-”这样可以非常的区分不同的接口路径,防止多接口时发生重复。接下来具体方法的上面可以定义于方法名一样的路径映射,我这里已 /hello1,/hello2,/hello3为主。

  1. public class User implements Serializable {
  2. private static final long serialVersionUID = -7233238826463139634L;
  3.  
  4. private Long id;
  5.  
  6. private String name;
  7.  
  8. private Integer age;
  9.  
  10. public User() {
  11. }
  12.  
  13. public User(String name, Integer age) {
  14. this.name = name;
  15. this.age = age;
  16. }
  17.  
  18. public Long getId() {
  19. return id;
  20. }
  21.  
  22. public void setId(Long id) {
  23. this.id = id;
  24. }
  25.  
  26. public String getName() {
  27. return name;
  28. }
  29.  
  30. public void setName(String name) {
  31. this.name = name;
  32. }
  33.  
  34. public Integer getAge() {
  35. return age;
  36. }
  37.  
  38. public void setAge(Integer age) {
  39. this.age = age;
  40. }
  41.  
  42. @Override
  43. public String toString() {
  44. return "User{" +
  45. "name='" + name + '\'' +
  46. ", age=" + age +
  47. '}';
  48. }
  49. }

上面就是简单的一个User对象。 

从上面的接口中发现,该api工程需要引入spring-web包。所以它的pom.xml如下:

  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.  
  7. <artifactId>hello-service-api</artifactId>
  8. <version>1.0-SNAPSHOT</version>
  9. <groupId>com.qee.hello</groupId>
  10.  
  11. <dependencies>
  12. <dependency>
  13. <groupId>org.springframework</groupId>
  14. <artifactId>spring-web</artifactId>
  15. <version>4.2.9.RELEASE</version>
  16. </dependency>
  17. </dependencies>
  18. </project>

  从上面的pom.xml定义中,我们知道hello-service-api并不集成父工程micro-service-integration。一般作为api提供的工程jar,依赖越少越好。

接下来我们需要创建一个提供者工程,我们把它命名为hello-service-compose。该工程也是标准的Spring Boot工程。具体的目录如下:

  在工程中我们有一个刚才hello-service-api接口定义的实现。代码如下:

  1. @RestController
  2. public class HelloServiceRemoteApiImpl implements HelloServiceRemoteApi {
  3.  
  4. @Override
  5. public String hello(@RequestParam("name") String name) {
  6. return "hello " + name;
  7. }
  8.  
  9. @Override
  10. public User hello(@RequestHeader("name") String name, @RequestHeader("age") Integer age) {
  11. try {
  12. name= URLDecoder.decode(name,"UTF-8");
  13. } catch (UnsupportedEncodingException e) {
  14. e.printStackTrace();
  15. }
  16. return new User(name, age);
  17. }
  18.  
  19. @Override
  20. public String hello(@RequestBody User user) {
  21. if (user == null) {
  22. return "未知";
  23. }
  24. return user.toString();
  25. }
  26. }

因为是测试工程,所以它没有复杂的业务逻辑。接下来就是HelloProviderApplication的启动main.

  1. package com.qee.remote;
  2.  
  3. import org.springframework.boot.SpringApplication;
  4. import org.springframework.boot.autoconfigure.SpringBootApplication;
  5. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  6.  
  7. @EnableDiscoveryClient
  8. @SpringBootApplication
  9. public class HelloProviderApplication {
  10.  
  11. public static void main(String[] args) {
  12. SpringApplication.run(HelloProviderApplication.class, args);
  13. }
  14. }

在上面有2个注解,第一个 SpringBootApplication 就是Spring Boot 启动注解,EnableDiscoveryClient 该注解会把RestController修饰的类注册到注册中心去。

接下来我们来看下application.properties

  1. server.port=8885
  2.  
  3. spring.application.name=hello-service-compose
  4.  
  5. eureka.instance.hostname=register.center.com
  6.  
  7. eureka.instance.server.port=8881
  8.  
  9. #默认的注册域
  10. eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/
  11.  
  12. #控制台彩色输出
  13. spring.output.ansi.enabled=ALWAYS

从上面信息我们知道,改工程启动端口为8885,注册中心地址为register.center.com:8881。

接下来我们查看一下该工程的pom.xml定义

  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. <parent>
  6. <artifactId>micro-service-integration</artifactId>
  7. <groupId>spring.cloud</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11.  
  12. <artifactId>hello-service-compose</artifactId>
  13.  
  14. <properties>
  15. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  16. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  17. </properties>
  18.  
  19. <dependencies>
  20. <dependency>
  21. <groupId>com.qee.hello</groupId>
  22. <artifactId>hello-service-api</artifactId>
  23. <version>1.0-SNAPSHOT</version>
  24. </dependency>
  25.  
  26. <dependency>
  27. <groupId>org.springframework.boot</groupId>
  28. <artifactId>spring-boot-starter-web</artifactId>
  29. </dependency>
  30.  
  31. <dependency>
  32. <groupId>org.springframework.cloud</groupId>
  33. <artifactId>spring-cloud-starter-eureka</artifactId>
  34. </dependency>
  35.  
  36. <dependency>
  37. <groupId>org.springframework.cloud</groupId>
  38. <artifactId>spring-cloud-starter-ribbon</artifactId>
  39. </dependency>
  40.  
  41. <dependency>
  42. <groupId>org.springframework.boot</groupId>
  43. <artifactId>spring-boot-starter-actuator</artifactId>
  44. </dependency>
  45.  
  46. </dependencies>
  47. </project>

  从pom.xml文件中知道该工程依赖了web,euraka,ribbon,actuator,hello-service-api 包。其中euraka为服务注册和发现包,ribbon为服务调用负载均衡包,actuator为工程元信息检测包。还有我们自己定义的hello-service-api包。

在上面的简单配置和编写后,我们就可以启动工程把该HelloServiceRemoteApi注册到注册中心去了。

  现在有了服务接口定义包和服务提供工程,现在我们编写一下服务调用工程。命名为hello-service-web。该工程的目录结构如下:

首先我们来看下HelloBackgroundService 这个接口。

  1. @FeignClient(value = "hello-service-compose")
  2. public interface HelloBackgroundService extends HelloServiceRemoteApi{
  3. }

 非常的简单,主要继承我们之前编辑的HelloServiceRemoteApi,并且在上面打上FeignClient注解,该注解指定服务名来绑定服务。该注解同时会使服务调用具有负载均衡的能力。

接下来我们来看下HelloController类

  1. @RestController
  2. public class HelloController {
  3.  
  4. @Autowired
  5. private HelloBackgroundService helloBackgroundService;
  6.  
  7. @RequestMapping("/hello")
  8. public Map<String,Object> hello(){
  9. Map<String,Object> ret = new HashMap<String, Object>();
  10. StringBuffer sb = new StringBuffer();
  11. String s1 = helloBackgroundService.hello("张三");
  12. sb.append(s1).append("\n");
  13. User user = null;
  14. try {
  15. user = helloBackgroundService.hello(URLEncoder.encode("李四", "UTF-8"), 30);
  16. } catch (UnsupportedEncodingException e) {
  17. e.printStackTrace();
  18. }
  19. sb.append(user.toString()).append("\n");
  20. String s3 = helloBackgroundService.hello(new User("王五", 19));
  21. sb.append(s3).append("\n");
  22. ret.put("show",sb.toString());
  23. return ret;
  24. }
  25. }

  从上面得知我们,我们就可以调用之前的我们编写的HelloBackgroundService了。接下来我们查看一下启动类HelloConsumerApp

  

  1. package com.qee;
  2.  
  3. import feign.Logger;
  4. import org.springframework.boot.SpringApplication;
  5. import org.springframework.boot.autoconfigure.SpringBootApplication;
  6. import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
  7. import org.springframework.cloud.netflix.feign.EnableFeignClients;
  8. import org.springframework.context.annotation.Bean;
  9.  
  10. @EnableFeignClients
  11. @EnableDiscoveryClient
  12. @SpringBootApplication
  13. public class HelloConsumerApp {
  14.  
  15. @Bean
  16. Logger.Level feginLoggerLevel(){
  17. return Logger.Level.FULL;
  18. }
  19.  
  20. public static void main(String[] args) {
  21. SpringApplication.run(HelloConsumerApp.class, args);
  22. }
  23. }

 在该启动了中又多了一个注解EnableFeignClients ,该注解开启Spring Cloud Feign的支持。接着我们来查看一下application.properties

  1. server.port=8887
  2.  
  3. spring.application.name=hello-service-web
  4.  
  5. eureka.instance.hostname=register.center.com
  6.  
  7. eureka.instance.server.port=8881
  8.  
  9. #默认的注册域
  10. eureka.client.serviceUrl.defaultZone=http://${eureka.instance.hostname}:${eureka.instance.server.port}/eureka/
  11.  
  12. #开启请求压缩功能
  13. feign.compression.request.enabled=true
  14.  
  15. #开启响应压缩功能
  16. feign.compression.response.enabled=true
  17.  
  18. #指定压缩请求数据类型
  19. feign.compression.request.mime-types=text/xml;application/xml;application/json
  20.  
  21. #如果传输超过该字节,就对其进行压缩
  22. feign.compression.request.min-request-size=2048
  23.  
  24. #控制台彩色输出
  25. spring.output.ansi.enabled=ALWAYS
  26.  
  27. #日志配置,该接口的日志级别
  28. logging.level.com.qee.service.HelloBackgroundService=DEBUG

 从上面的注释中,我们已经可以知道具体的配置参数的作用,这里就不详细介绍了。从上面的配置和编写我们可以知道,该工程需要如下的依赖包,pom.xml文件如下

  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. <parent>
  6. <artifactId>micro-service-integration</artifactId>
  7. <groupId>spring.cloud</groupId>
  8. <version>1.0-SNAPSHOT</version>
  9. </parent>
  10. <modelVersion>4.0.0</modelVersion>
  11.  
  12. <artifactId>hello-service-web</artifactId>
  13.  
  14. <properties>
  15. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  16. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
  17. </properties>
  18.  
  19. <dependencies>
  20. <dependency>
  21. <groupId>com.qee.hello</groupId>
  22. <artifactId>hello-service-api</artifactId>
  23. <version>1.0-SNAPSHOT</version>
  24. </dependency>
  25.  
  26. <dependency>
  27. <groupId>org.springframework.boot</groupId>
  28. <artifactId>spring-boot-starter-web</artifactId>
  29. </dependency>
  30.  
  31. <dependency>
  32. <groupId>org.springframework.cloud</groupId>
  33. <artifactId>spring-cloud-starter-eureka</artifactId>
  34. </dependency>
  35.  
  36. <dependency>
  37. <groupId>org.springframework.cloud</groupId>
  38. <artifactId>spring-cloud-starter-ribbon</artifactId>
  39. </dependency>
  40.  
  41. <dependency>
  42. <groupId>org.springframework.cloud</groupId>
  43. <artifactId>spring-cloud-starter-feign</artifactId>
  44. </dependency>
  45.  
  46. <dependency>
  47. <groupId>org.springframework.boot</groupId>
  48. <artifactId>spring-boot-starter-actuator</artifactId>
  49. </dependency>
  50.  
  51. </dependencies>
  52. </project>

  该服务消费端,比服务提供方多了一个jar依赖,就是feign。该jar的作用就是提供声明式的服务调用。到这里我们本章的内容大致结束,最后我们来运行这几个工程。查看如下结果:

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

到这里服务注册中心启动,服务注册,服务消费大致都已完成,之后会向大家一起学习服务调用的负载均衡Ribbon和服务容错保护Hystrix.

 

Spring Cloud 声明式服务调用 Feign的更多相关文章

  1. SpringCloud 源码系列(6)—— 声明式服务调用 Feign

    SpringCloud 源码系列(1)-- 注册中心 Eureka(上) SpringCloud 源码系列(2)-- 注册中心 Eureka(中) SpringCloud 源码系列(3)-- 注册中心 ...

  2. SpringCloud之声明式服务调用 Feign(三)

    一 Feign简介 Feign是一种声明式.模板化的HTTP客户端,也是netflix公司组件.使用feign可以在远程调用另外服务的API,如果调用本地API一样.我们知道,阿里巴巴的doubbo采 ...

  3. SpringCloud开发学习总结(七)—— 声明式服务调用Feign(一)

    在实践的过程中,我们会发现在微服务架构中实现客户端负载均衡的服务调用技术Spring Cloud Ribbon<SpringCloud开发学习总结(四)—— 客户端负载均衡Ribbon> ...

  4. 004声明式服务调用Feign & 断路器Hystrix

    1.POM配置 和普通Spring Boot工程相比,添加了Eureka Client.Feign.Hystrix依赖和Spring Cloud依赖管理 <dependencies> &l ...

  5. spring cloud 声明式rest客户端feign调用远程http服务

    在Spring Cloud Netflix栈中,各个微服务都是以HTTP接口的形式暴露自身服务的,因此在调用远程服务时就必须使用HTTP客户端.Feign就是Spring Cloud提供的一种声明式R ...

  6. Spring Cloud Feign 1(声明式服务调用Feign 简介)

    Spring Cloud Feign基于Netflix Feign 同时整合了Spring Cloud Ribbon和Spring Cloud Hytrix,除了提供两者的强大功能外,它还提供了一种声 ...

  7. Spring Cloud第七篇 | 声明式服务调用Feign

    本文是Spring Cloud专栏的第七篇文章,了解前六篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Cloud ...

  8. 【Dalston】【第三章】声明式服务调用(Feign)

    当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻.那 ...

  9. 声明式服务调用Feign

    什么是 Feign Feign 是种声明式.模板化的 HTTP 客户端(仅在 consumer 中使用).   什么是声明式,有什么作用,解决什么问题? 声明式调用就像调用本地方法一样调用远程方法;无 ...

随机推荐

  1. Poptest学员之当小厨师变成测试开发工程师

    没开玩笑,这是我们的真实案例.做培训以来,各行各业转行做测试的学员见得太多了.修车的.客服的.销售的.司机的.医护的.前台的等等.职位虽然不分贵贱,但是薪资却分多少.每个人心中都有让家人和自己过上好日 ...

  2. 老李分享:大数据测试之HDFS文件系统

    poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:908821478,咨询电话010-845052 ...

  3. 在centOS7.2安装配置zabbix监控

    zabbix由两部分组成,zabbix-server与可选的zabbix-agent.zabbix-server可以通过SNMP,ZABBIX-AGENT,PING,端口监视等方法提供对远程服务器/网 ...

  4. LoonAndroid自动检测输入框 --- Author: rose && lvyerose@163.com

    LoonAndroid框架,同时给我们提供了一套自动检测输入规则的工具,用起来很是方便,下面介绍一下这个东东的使用方法(注意,该说明是基于项目已经集成了LoonAndroid框架而言,如果您未集成该框 ...

  5. 2.Maven 使用

    1 Maven使用 1.1 编写POM 就像Make的Makefile,Ant的build.xml一样,Maven项目的核心是pom.xml. 首先创建一个名为hello-world的文件夹(本书中各 ...

  6. ecshop SQL注入漏洞导致代码执行

    漏洞名称:ecshop SQL注入漏洞导致代码执行补丁编号:11208761补丁文件:/includes/libinsert.php补丁来源:云盾自研漏洞描述:ecshop的/includes/lib ...

  7. ajax 第四步

    Ajax和XMLHttpRequest详述 (2011-12-10 16:40:23) 转载▼ 标签: ajax xmlhttprequest 分类: Web Ajax:Asynchronous Ja ...

  8. 移动开发中使用的一些meta头部标签整理

    <!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...

  9. alert 和 console.log的区别

    出走半月,一直以为 console.log 和 alert 的用法是一样的,只是表现的形式不同,alert 是以弹框的形式出现,console.log 是在后台打印输出. 但是今天在写东西的时候,发现 ...

  10. 自然梯度(Natural Gradient)

    自然梯度(Natural Gradient)