Spring Cloud系列教程(五) - 服务消费者Feign+Ribbon(Finchley版本)

一、前言

SpringCloud微服务框架中,生产者提供消息注册到注册中心,消费者从注册中心获取生产者提供的服务接口调用地址,进行消息的消费;那么在SpringCloud微服务中,消费者消费调用生产者的服务有两种形式:Rest+RibbonFeign这两种方式,Rest+Ribbon在前面章节已经学习过,这里主要介绍下使用Feign方式如何消费消息;

二、Feign是什么

Feign是一个声明式的Web服务客户端工具,只要指定服务名,就可以将调用具体的服务接口,使用Feign,只需要创建一个接口并注解。它具有可插拔的注解特性,可使用Feign 注解和JAX-RS注解。Feign支持可插拔的编码器和解码器。Feign默认集成了Ribbon组件,并和Eureka结合,并且默认是通过轮询实现了负载均衡的效果。 同时Spring CloudFeign进行了增强,使Feign支持 Spring Mvc的注解,并整合了 Ribbon等,从而让微服务的调用更加方便,Feign客户端调用工具这才真正意义上实现了面向接口调用微服务

1. 如何使用Feign

只需要创建一个接口,然后在上面添加@FeignClient(value = “服务名”)注解;
通过这个注解和指定的服务名称可以绑定远程微服务实例,服务名称可以大写也可以小写;
通过@RequestMapping(“/方法名”)来指定远程服务提供者提供的那个方法;

使用Feign,只需引入依赖: spring-cloud-starter-openfeign 组件即可; 仔细观察引入Feign组件后的依赖信息:
Feign默认集成了Hystrix
在这里插入图片描述
关于Feign客户端调用工具,可以总结为以下三点:

  • Feign 采用的是基于接口的注解
  • Feign 整合了ribbon,具有负载均衡的能力
  • Feign 整合了Hystrix,具有服务保护、熔断的能力

三、环境准备

依据前面章节第二节搭建的springcloud-eureka-server 端口为8000springcloud-app-member 端口为8762,先启动springcloud-eureka-server 端口为8000Eureka注册中心;然后修改springcloud-app-member中的getMember接口,新增一个接受参数userName,接下来启动会员服务两次,端口分别为8762和8765,为了后续演示Feign负载均衡效果,具体如下:

package com.thinkingcao.api.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @desc:   会员服务接口
 * @author: cao_wencao
 * @date: 2020-02-19 18:12
 */
@RestController
public class MemberController {

    @Value("${server.port}")
    private String serverPort;

    //会员服务接口
    @RequestMapping("/getMember")
    private String getMember(@RequestParam("userName") String userName) {
        return "我是会员服务,订单服务调用会员服务成功啦, 端口号为: " + serverPort +"——用户名: "+ userName;
    }
}

四、创建一个Feign的服务

1. 新建springcloud-feign-client

在父工程的基础上新增module,名字为springcloud-feign-client,依赖如下:

  <!--SpringBoot依赖版本-->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.thinkingcao</groupId>
    <artifactId>springcloud-feign-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-feign-client</name>
    <description>SpringCloud整合Feign客户端组件消费服务</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Finchley.RELEASE</spring-cloud.version>
    </properties>

    <!--声明管理SpringCloud版本依赖信息-->
    <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>

    <dependencies>
        <!-- SpringBootWeb组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- springcloud整合eureka客户端组件   -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <!-- springcloud整合Feign客户端组件   -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

        <!--lombok代码简化工具-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

2. 配置application.yml

##=========服务消费者-订单服务配置========
#服务端口号
server:
  port: 8787
#定义服务名称(服务注册到eureka名称)
spring:
  application:
    name: app-thinkingcao-feign
#在此指定服务注册中心地址,将当前订单服务注册到eureka注册中心上
eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:8000/eureka
    #启动注册操作,该值默认为true。若设置为fasle将不会启动注册操作。是否需要去检索寻找服务,默认是true
    register-with-eureka: true
    #是否需要从eureka上获取注册信息
    fetch-registry: true
    #表示eureka client间隔多久去拉取服务器注册信息,默认为30秒
    registry-fetch-interval-seconds: 10

  ##心跳检测与续约时间(测试环境和本地开发环境将值设置小一点,保证服务关闭后,注册中心能够及时踢出)
  instance:
    #客户端向Eureka注册中心发送心跳的时间间隔,单位为秒(默认为30s),(客户端会按照此规则向Eureka服务端发送心跳检测包)
    lease-renewal-interval-in-seconds: 2
    #Eureka注册中心在收到客户端最后一次心跳之后等待的时间上限,单位为秒(默认为90s),超过时间则剔除(客户端会按照此规则向Eureka服务端发送心跳检测包)
    lease-expiration-duration-in-seconds: 2

3. 创建一个Feign接口

定义一个feign接口,通过@FeignClient(“服务名”),来指定调用哪个微服务服务。比如我要调用springcloud-app-member中的getMember接口,则在接口中的方法@RequestMapping(“方法名”)注解中指定微服务的方法名字,表明调用该微服务实例中的哪一个方法,如果式企业开发中springcloud-app-member中声明了接口层,可直接用IFeignClientService 集成会员服务的接口,此时可以使用其全部的定义的方法,IFeignClientService 中无需再定义,这样方便简洁代码的开发;

  • IFeignClientService如下
package com.thinkingcao.api.Feign;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

/**
 * @desc: Feign声明式客户端调用工具
 * @author: cao_wencao
 * @date: 2020-02-22 12:23
 */
@FeignClient(value = "app-thinkingcao-member")
public interface IFeignClientService {

    //通过userId查询会员信息数据
    @RequestMapping("/getMember")
    public String getOrderToMemberInfo(@RequestParam("userName") String userName);

}

4. 暴露API接口

Feign微服务中的controller层中,对外暴露一个"getOrderToMemberInfo"API接口,通过上面定义的Feign客户端IFeignClientService 来消费服务。代码如下:

  • ApiOrderController
package com.thinkingcao.api.controller;

import com.thinkingcao.api.Feign.IFeignClientService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @desc:
 * @author: cao_wencao
 * @date: 2020-02-22 12:30
 */
@RestController
public class ApiOrderController {

    @Autowired(required=false)
    private IFeignClientService feignClientService;

    @RequestMapping(value = "/getOrderToMemberInfo",method = RequestMethod.GET)
    public String getOrderToMemberInfo(@RequestParam("userName") String userName){
        String memberInfo = feignClientService.getOrderToMemberInfo(userName);
        return memberInfo;
    }

}

5. 启动类

通过@EnableFeignClients注解开启Feign客户端调用工具服务,通过@EnableEurekaClient注解开启Eureka客户端。表示向Eureka服务端注册和获取服务信息;

  • AppFeignClient
package com.thinkingcao.api;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class AppFeignClient {

    public static void main(String[] args) {
        SpringApplication.run(AppFeignClient.class, args);
    }
}

6. 项目完整结构

在这里插入图片描述

五、测试

1. 测试

依次启动AppEurekaServerAppMemberProvider(启动两次,分别为8762和8765端口)AppFeignClient,多次访问请求:http://127.0.0.1:8787/getOrderToMemberInfo?userName=“Thinkingcao”,浏览器交替显示如下结果:

  • 我是会员服务,订单服务调用会员服务成功啦, 端口号为: 8765——用户名: “Thinkingcao”
  • 我是会员服务,订单服务调用会员服务成功啦, 端口号为: 8762——用户名: “Thinkingcao”
  • 启动服务效果图
    -在这里插入图片描述
  • 8762效果图
    在这里插入图片描述
  • 8765效果图
    在这里插入图片描述

2. 总结

  • Feign默认支持负载均衡能力,默认使用的是轮询机制;
  • Feign更适合于企业项目开发中服务消费的方式;

六、源码

1. 项目源码: https://github.com/Thinkingcao/SpringCloudLearning/tree/master/springcloud-feign

七、SpringCloud系列教程

1. SpringCloud系列教程(三): Spring Cloud系列教程(六):服务注册与发现Consul(Finchley版本)

SpringCloud教程汇总: Spring Cloud系列教程(汇总篇):专栏汇总篇(持续更新中)

Thinkingcao CSDN认证博客专家 Java Spring Boot 架构
CSDN2019年度博客之星、博客专家,专注架构、Java、SpringBoot、SpringCloud、Spring、微服务、分布式等领域

nacos作为注册中心,启动后会寻找我未注册的服务(数据库ip的服务名)

07-02
``` 2019-07-02 14:48:17.850 ERROR [smallcircle-member,,,] 11616 --- [.naming.updater] com.alibaba.nacos.client.naming : [] [] [CALL-SERVER] failed to req API:http://127.0.0.1:8848/nacos/v1/ns/api/srvIPXT. code:404 msg: service not found: DEFAULT_GROUP@@47.98.52.252 2019-07-02 14:48:17.851 ERROR [smallcircle-member,,,] 11616 --- [.naming.updater] com.alibaba.nacos.client.naming : [] [] [NA] req api:/nacos/v1/ns/api/srvIPXT failed, server(127.0.0.1:8848 com.alibaba.nacos.api.exception.NacosException: null at com.alibaba.nacos.client.naming.net.NamingProxy.callServer(NamingProxy.java:304) [nacos-client-0.6.2.jar:na] at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:327) [nacos-client-0.6.2.jar:na] at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:310) [nacos-client-0.6.2.jar:na] at com.alibaba.nacos.client.naming.net.NamingProxy.reqAPI(NamingProxy.java:257) [nacos-client-0.6.2.jar:na] at com.alibaba.nacos.client.naming.core.HostReactor.updateServiceNow(HostReactor.java:340) [nacos-client-0.6.2.jar:na] at com.alibaba.nacos.client.naming.core.HostReactor$UpdateTask.run(HostReactor.java:429) [nacos-client-0.6.2.jar:na] at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_171] at java.util.concurrent.FutureTask.run$$$capture(FutureTask.java:266) [na:1.8.0_171] at java.util.concurrent.FutureTask.run(FutureTask.java) [na:1.8.0_171] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_171] at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293) [na:1.8.0_171] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171] at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171] 2019-07-02 14:48:17.852 ERROR [smallcircle-member,,,] 11616 --- [.naming.updater] com.alibaba.nacos.client.naming : [] [] [NA] failed to update serviceName: 47.98.52.252 ```
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值