spring cloud 入门系列五:使用Feign 实现声明式服务调用

一、SpringCloudFeign概念引入通过前面的随笔,我们了解如何通过SpringCloudribbon进行负责均衡,如何通过SpringCloudHystrix进行服务断路保护,两

大家好,又见面了,我是全栈君。

一、Spring Cloud Feign概念引入
通过前面的随笔,我们了解如何通过Spring Cloud ribbon进行负责均衡,如何通过Spring Cloud Hystrix进行服务断路保护,
两者作为基础工具类框架应用在各种基础设施类微服务和业务类微服务中,并且成对存在,那么有没有更高层的封装,将两者的使用
进一步简化呢? 有! 他就是Spring Cloud Feign。它基于Netflix Feign实现,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,
除了提供两者强大的功能外,还提供了一种声明式的Web服务客户端定义方式。

二、入门实例
我们还是继续使用前面随笔中的hello-service服务,这里通过Spring Cloud Feign提供的声明式服务绑定功能来实现对服务接口的调用。
我们需要新建一个feign-consumer来代替之前的hello-consumer

先给出代码结构:

  spring cloud 入门系列五:使用Feign 实现声明式服务调用

代码实现:

  1. 新建maven工程(feign-consumer)
  2. 修改pom文件,引入eureka和feign依赖
    <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>com.sam</groupId>
      <artifactId>feign-consumer</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      
      <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.1.RELEASE</version>
        </parent>
    
        <properties>
            <javaVersion>1.8</javaVersion>
        </properties>
    
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Camden.SR6</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
    
        </dependencyManagement>
    
        <dependencies>
            <!-- 引入eureka 客户端依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <!-- 引入feign 依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
            </dependency>
    
        </dependencies>
        
    </project>

  3. 新建启动类
    /**
     * 通过@EnableFeignClients来开启spring cloud feign的支持功能
     *
     */
    @EnableFeignClients
    @EnableDiscoveryClient
    @SpringBootApplication
    public class FeiApp {
    
        public static void main(String[] args) {
            SpringApplication.run(FeiApp.class, args);
        }
    
    }

  4. 新建service接口
    /**
     * 通过@FeignClient注解指定服务名来绑定服务,这里的服务名字不区分大小写
     * 然后再通过@RequestMapping来绑定服务下的rest接口
     *
     */
    @FeignClient(name="hello-service")
    public interface FeignConsumerService{
    
        @RequestMapping("/hello")
        public void hello();
    }

  5. 新建controller
    @RestController
    public class FeiConsumerController {
    
        @Autowired
        FeignConsumerService consumerService;
    
        @RequestMapping("feign-consumer")
        public String feignConsumer() {
            consumerService.hello();
            return "feign consumer call finished!!!";
        }
    
    }

  6. 新建application.properties
    server.port=9001
    
    spring.application.name=feign-consumer
    
    eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka

  7. 测试,
    1. 启动服务注册中心eureka、启动两个hello-service(端口号分别为9090和9091),启动feign-consumerspring cloud 入门系列五:使用Feign 实现声明式服务调用

       

    2. 访问http://localhost:9001/feign-consumer

       

      spring cloud 入门系列五:使用Feign 实现声明式服务调用

      并且多次访问的话,会轮询调用两个hello-service服务。

 

三、参数绑定
在上面的例子中,我们实现的只是一个不带参数的rest服务绑定,然而现实的业务中不会这么简单,往往会有各种参数,
这个时候我们做如下事情:

  1. 如果服务提供方有对象参数(如User对象),那么feign-consumer工程中需要建一个路径和类名完全一样的类。
  2. 然后将服务提供方controller里面的所有方法声明进行copy(包括前面的@RequestMapping),粘贴到feign-consumer的service接口里面。

四、继承特性
根据上面参数绑定的做法,我们需要进行很多copy操作,这样比较麻烦,可以通过继承的方式进行简化。

这种实现步骤如下:

1.我们需要新建一个基础工程hello-service-api,

  代码结构:

  spring cloud 入门系列五:使用Feign 实现声明式服务调用

  代码实现:

  1. )新建maven项目hello-service-api
  2. )修改pom文件
    <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>com.sam</groupId>
      <artifactId>hello-service-api</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      
      <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.1.RELEASE</version>
        </parent>
    
        <properties>
            <javaVersion>1.8</javaVersion>
        </properties>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            
        </dependencies>
    </project>

    你会发现其实就是一个普通的spring boot项目。

  3. )考虑到需要掩饰参数中有对象的情况,我们加个User类
    package com.sam.entity;
    
    public class User {
    
        private String name;
        private Integer age;
    
        
        public User(String name, Integer age) {
            super();
            this.name = name;
            this.age = age;
        }
        
    
        public User() {
            super();
        }
    
    
    
        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;
        }
    
    }

    User必须要有一个无参数的构造器。

  4. )新建service接口
    /**
     * 为了同前面那个hello 接口区分开了,我们加了refactor前缀
     *
     */
    @RequestMapping("/refactor")
    public interface HelloService {
    
        @RequestMapping("/hello2")
        public String hello2();
        
        @RequestMapping("/hello3")
        public User printUser(@RequestBody User user);
    }

2.重构hello-sevice服务

  1. )修改pom文件
    <!-- 引入 hello-service-api的依赖,以继承其提供的接口 -->
            <dependency>
                <groupId>com.sam</groupId>
                <artifactId>hello-service-api</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>

  2. )HelloController implements HelloService,并实现interface中的接口
    @RestController
    public class HelloController implements HelloService{
    
        Logger logger = LoggerFactory.getLogger(HelloController.class);
    
        @Autowired
        DiscoveryClient discoveryClient;
        
        @RequestMapping("/hello")
        public String hello() throws Exception {
            ServiceInstance instance = discoveryClient.getLocalServiceInstance();
            //打印服务的服务id
            logger.info("*********" + instance.getServiceId());
            return "hello,this is hello-service";
        }
    
        @Override public String hello2() { return "hello,this is hello2-service"; } @Override public User printUser(@RequestBody User user) { return user; } 
    }

    controller实现接口的方法时,不需要@RequestMapping注解,只需要类注解@RestController即可。

3.重构feign-consumer服务

  1. )修改POM文件
    <!-- 引入 hello-service-api的依赖,以继承其提供的接口 -->
            <dependency>
                <groupId>com.sam</groupId>
                <artifactId>hello-service-api</artifactId>
                <version>0.0.1-SNAPSHOT</version>
            </dependency>

  2. )让FeignConsumerService extends hello-service-api中的HelloService
    /**
     * 通过@FeignClient注解指定服务名来绑定服务,这里的服务名字不区分大小写
     * 然后再通过@RequestMapping来绑定服务下的rest接口
     *
     */
    @FeignClient(name="hello-service")
    public interface FeignConsumerService extends HelloService{
    
        @RequestMapping("/hello")
        public void hello();
    }

    只需要继承即可。

  3. )修改controller,追加方法
    @RestController
    public class FeiConsumerController {
    
        @Autowired
        FeignConsumerService consumerService;
    
        @RequestMapping("feign-consumer")
        public String feignConsumer() {
            consumerService.hello();
            return "feign consumer call finished!!!";
        }
     @RequestMapping("feign-consumer-user") public User feignConsumer2(User user) { consumerService.hello2(); return consumerService.printUser(user); }
    }

     

4.测试

spring cloud 入门系列五:使用Feign 实现声明式服务调用

 

五、其他
由于Spring Cloud Feign是通过ribbon和hystrix实现具体功能的,因此可以直接通过配置这两个来实现功能
1.ribbon配置方式:
  通过ribbon.<key>=<value>的方式进行全局配置,比如
    ribbon.ConnectTimeout=500
    ribbon.ReadTimeout=5000
  通过<client>.ribbon.<key>=<value>的方式进行指定服务配置,比如
    #这里的<client>为@FeignClient(value=”hello-service”)指定的服务名
    hello-service.ribbon.ConnectTimeout=500
    hello-service.ribbon.ReadTimeout=500
2.hystrix配置方式:
  通过hystrix.command.default.xxx进行全局配置
    如:hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=5000
  通过hystrix.command.<commandKey>.xxx进行指定配置,这里的<commandKey>可以为方法名
    如:hystrix.command.hello.execution.isolation.thread.timeoutInMilliseconds=5000
3.请求压缩配置,支持对请求和响应进行GZIP压缩,以减少通信过程中的性能损耗。
  feign.compression.request.enabled=true;

  feigan.compression.response.enabled=true;

4.日志配置
  Spring Cloud Feign在构建被@FeignClient注解修饰的服务客户端是,会为每一个客户端都创建一个feign.Logger实例,我们可以利用该日志对象进行Log分析。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/120906.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 解决Symantec卸载需要密码问题又一新招

    解决Symantec卸载需要密码问题又一新招今天在同事哪里学到卸载SYMANTEC需要密码又一新招,看图就知道了,对!就是修改注册表,在LOCAL_MACHINE—SOFTWARE—SYMANTEC—SYMANTECENDPOINTPRTECTION—SECURITY找到UseVPUninstallPassword键值,修心DWORD值,看图就知道了哈,说多了废话.我这里是SEP注册表…

    2022年5月20日
    206
  • CreateThread()与_beginthread()的区别详细解析

    很多开发者不清楚这两者之间的关系,他们随意选一个函数来用,发现也没有什么大问题,于是就忙于解决更为紧迫的任务去了。等到有一天忽然发现一个程序运行时间很长的时候会有细微的内存泄露,开发者绝对不会想到是因为这两套函数用混的结果我们知道在Windows下创建一个线程的方法有两种,一种就是调用WindowsAPICreateThread()来创建线程;另外一种就是调用MSVC…

    2022年4月4日
    55
  • 以太坊(ETH)挖矿最新教程_以太坊个人挖矿

    以太坊(ETH)挖矿最新教程_以太坊个人挖矿以太坊(ETH)挖矿最新教程目前网上的大多数以太坊挖矿教程是很早整理编写的,基本都已过时不适用了。但挖矿是一个技术持续升级更新的过程,因此根据最新实战情况编写了本文,并争取在以后抽时间持续保持跟进更新。一.基本要求ETH 挖矿主要是使用显卡来挖矿。因此你需要一台拥有以下设备的PC(矿机):显卡、主板、电源、CPU、内存(推荐4G)、硬盘(推荐60G的SSD)、PCI-E转接线

    2022年10月15日
    2
  • 怎么反编译dll文件(反编译dll查看源代码)

    DLL(DynamicLinkLibrary)文件为动态链接库文件,又称“应用程序拓展”,是软件文件类型。下载并解压.NETReflector,下面下载为绿色7.3.0.18版本;(注:此为英文版,百度有汉化版下载)链接:https://pan.baidu.com/s/1eoWFe62wA_uOdn3wTQ7e-w密码:gt87…

    2022年4月12日
    100
  • Java:详解Java中的异常(Error与Exception)[通俗易懂]

    Java:详解Java中的异常(Error与Exception)[通俗易懂]一、异常机制的概述异常机制是指当程序出现错误后,程序如何处理。具体来说,异常机制提供了程序退出的安全通道。当出现错误后,程序执行的流程发生改变,程序的控制权转移到异常处理器。程序错误分为三种:1.编译错误;2.运行时错误;3.逻辑错误。(1)编译错误是因为程序没有遵循语法规则,编译程序能够自己发现并且提示我们错误的原因和位置,这个也是大家在刚接触编程语言最常遇到的问题。(2)运行时错误是因为程序在执行时,运行环境发现了不能执行的操作。(3)…

    2022年7月7日
    22
  • Asp.Net enableEventValidation

    Asp.Net enableEventValidationasp.net中enableEventValidation是干什么的???回发或回调参数无效。在配置中使用<pagesenableEventValidation=”true”/>或在页面中使用<%@PageEnableEventValidation=”true”%>启用了事件验证。出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现…

    2022年7月26日
    9

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号