zoukankan      html  css  js  c++  java
  • Spring Cloud Feign声明式服务调用(转载)+遇到的问题

    转载:原文

    总结:

    1.pom添加依赖

    2.application中填写正确的eureka配置

    3.启动项中增加注解

    @EnableFeignClients

    4.填写正确的调用接口

    通过原文使用Feign可能会遇到的问题

    Eureka中配置的地址不对,导致消费者调用提供者方法时候,出现链接超时, 这边需要改一下提供者的Eureka的接口配置

    正文如下

    一、Feign介绍
    Feign是一个声明式的伪Http客户端,通过Feign可以实现服务间的相互调用,比如服务A调用服务B暴露的一些接口;同时Feign整合了Ribbon,所以Feign也可以实现服务的负载均衡调用。想要使用Feign也比较简单,定义一个通过注解@FeignClient()指定需要调用的服务的接口,启动类加上@EnableFeignClients开启Feign功能即可。

    二、准备工作:
    本文同样有三个工程,分别是:

    eureka-server: 服务注册中心,端口1111;

    feign-service-a: Feign客户端,端口2222;

    feign-service-b: 服务提供者,端口3333和4444,需要启动多个实例;

    本文主要演示如何在feign-service-a通过feign远程调用feign-service-b中暴露的接口。

    三、新建feign-service-b工程
    首先引入依赖:

    <?xml version="1.0" encoding="UTF-8"?>
    <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.springcloud.wsh</groupId>
        <artifactId>springcloud_feign_service_b</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
     
        <name>springcloud_feign_service_b</name>
        <description>Feign 服务B</description>
     
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.2.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
     
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
            <spring-cloud.version>Camden.SR6</spring-cloud.version>
        </properties>
     
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
     
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
     
        <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>
     
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    </project>


     

    四、新建feign-service-a的配置文件application.yml

    server:
    #  port: 3333
      port: 4444
    spring:
      application:
        name: eureka-feign-service-b
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:1111/eureka/


    同时启动类加上@EnableDiscoverClient,使其注册到Eureka中

    @SpringBootApplication
    @EnableDiscoveryClient
    public class SpringcloudFeignServiceBApplication {
     
        public static void main(String[] args) {
            SpringApplication.run(SpringcloudFeignServiceBApplication.class, args);
        }
    }


    五、新建FeignServiceBController.java
    该类主要暴露接口给其他服务调用

    /**
     * @Title: FeignServiceBController
     * @ProjectName springcloud_feign
     * @Description: 服务BController
     * @Author WeiShiHuai
     * @Date 2018/9/10 15:07
     */
    @RestController
    public class FeignServiceBController {
     
        private static Logger logger = LoggerFactory.getLogger(FeignServiceBController.class);
     
        @Autowired
        private DiscoveryClient discoveryClient;
     
        @RequestMapping("/getInfo")
        public String getInfo(@RequestParam("name") String name) {
            ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance();
            String host = serviceInstance.getHost();
            Integer port = serviceInstance.getPort();
            String info = "hello, name = " + name + ", host = " + host + ", port = " + port;
            logger.info(info);
            return info;
        }
     
    }


    至此,feign-service-b功能已经搭建成功。启动eureka-server以及启动两个feign-service-b实例,用于测试服务的负载均衡调用。

    访问http://localhost:1111/可以看到已经成功启动两个feign-service-b实例,端口号分别是3333和4444:

    六、新建feign-service-a工程
    首先引入pom依赖,注意需要引入Feign的依赖。

    <?xml version="1.0" encoding="UTF-8"?>
    <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.springcloud.wsh</groupId>
        <artifactId>springcloud_feign_service_a</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <packaging>jar</packaging>
     
        <name>springcloud_feign_service_a</name>
        <description>Feign服务A</description>
     
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>1.5.2.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
     
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.8</java.version>
            <spring-cloud.version>Camden.SR6</spring-cloud.version>
        </properties>
     
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-eureka</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-starter-feign</artifactId>
            </dependency>
     
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
     
        <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>
     
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
     
    </project>
     



    七、新建feign-service-a的配置文件

    server:
      port: 2222
    spring:
      application:
        #应用名称,Feign通过@FeignClient指定服务名称进行调用
        name: eureka-feign-service-a
    eureka:
      client:
        service-url:
          defaultZone: http://localhost:1111/eureka/


    八、启动类加上注解@FeignClients以及@EnableDiscoverClient
    @FeignClients:主要开启Feign的声明式服务调用功能

    @EnableDiscoverClient: 主要注册成为Eureka的一个客户端

    /**
     * @Description: Feign远程服务调用(这里模拟A服务通过远程服务调用B服务的接口)
     * @Author: WeiShiHuai
     * @Date: 2018/9/10 15:01
     * Feign是一个声明式的Web Service客户端,使用Feign来创建一个接口并用@FeignClient注解来配置它既可。
     * Spring Cloud为Feign增加了对Spring MVC注解的支持,还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。
     * 通过Feign远程服务调用,方便了各个服务之间的接口调用,就像调用本地方法一样。
     */
    @SpringBootApplication
    @EnableDiscoveryClient
    //@EnableFeignClients注解用于开启Feign远程服务调用功能
    @EnableFeignClients
    public class SpringcloudFeignServiceAApplication {
     
        public static void main(String[] args) {
            SpringApplication.run(SpringcloudFeignServiceAApplication.class, args);
        }
    }


    九、新建FeignClient
    FeignClient必须是一个接口,类需要加上@FeignClient指定需要调用的服务名称,这个对应application-name,同时可以指定fallback回调方法,这个在feign调用失败的时候执行。

    /**
     * @Title: ServiceBFeignClient
     * @ProjectName springcloud_feign
     * @Description: FeignClient
     * @Author WeiShiHuai
     * @Date 2018/9/10 15:15
     * 1. FeignClient必须是一个接口interface
     * 2. 必须加上@FeignClient指定需要调用哪个服务的接口
     * 3. Feign默认集成了Ribbon,所以通过Feign也可以实现服务的负载均衡调用(轮询方式)。
     *
     * Feign的实现的过程大致如下:
        a. 首先通过@EnableFeignClients注解开启FeignClient
        b. 根据Feign的规则实现接口,并加@FeignClient注解
        c. 程序启动后,会进行包扫描,扫描所有的@ FeignClient的注解的类,并将这些信息注入到ioc容器中。
        d. 当接口的方法被调用,通过jdk的代理,来生成具体的RequestTemplate
        e. RequestTemplate在生成Request
        f. Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp
        g. 最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡
     *
     */
     //@FeignClient注解通过value指定调用的服务名称,对应application.yml的application-name,如本例为eureka-feign-service-b
    //通过fallback指定远程服务调用失败的回调方法,也叫服务降级处理,回调类必须实现使用@FeignClient标识的接口(implements ServiceBFeignClient)
    //使用@FeignClient("eureka-feign-service-b")注解来绑定该接口对应feign-service-b服务
    @FeignClient(value = "eureka-feign-service-b", fallback = ServiceBFeignClientFallback.class)
    public interface ServiceBFeignClient {
     
        /**
         * 编写Feign接口简便的方法:把具体需要远程调用的服务(如服务B)中的方法复制过来,去掉实现即可。
         *
         * @param name
         * @return
         */
        @RequestMapping("/getInfo")
        String getInfo(@RequestParam("name") String name);
     
    }



    同时,新建ServiceBFeignClientFallback.java指定Feign失败回调方法

    /**
     * @Title: ServiceBFeignClientFallback
     * @ProjectName springcloud_feign
     * @Description: FeignClient失败回调方法
     * @Author WeiShiHuai
     * @Date 2018/9/10 15:22
     * FeignClient失败回调方法必须实现使用@FeignClient标识的接口(implements ServiceBFeignClient),实现其中的方法
     */
    @Component
    public class ServiceBFeignClientFallback implements ServiceBFeignClient {
     
        /**
         * 当服务B由于某种原因使得服务调用不成功时会执行该回调方法
         *
         * @param name
         * @return
         */
        @Override
        public String getInfo(String name) {
            return "sorry " + name + ", feign client error";
        }
     
    }


    十、新建FeignController.java
    通过注入上面定义的ServiceBFeignClient,实现服务间的调用

    /**
     * @Title: FeignController
     * @ProjectName springcloud_feign
     * @Description: 测试Feign
     * @Author WeiShiHuai
     * @Date 2018/9/10 15:28
     * 注入FeignClient,调用feignClient的方法实现远程方法调用
     */
    @RestController
    public class FeignController {
     
        private static Logger logger = LoggerFactory.getLogger(FeignController.class);
     
        @Autowired
        private ServiceBFeignClient serviceBFeignClient;
     
        /**
         * 使用http://localhost:2222/getInfo访问,实际上A服务会通过FeignClient调用服务B提供的getInfo接口
         *
         * @param name
         * @return
         */
        @GetMapping("/getInfo")
        public String getInfo(@RequestParam("name") String name) {
            String info = serviceBFeignClient.getInfo(name);
            logger.info(info);
            return info;
        }
     
    }


    十一、测试
    启动feign-service-a工程,访问http://localhost:1111/,可以看到成功注册到Eureka:

    此时访问http://localhost:2222/getInfo?name=weixiaohuai,可以看到我们已经通过Feign实现了在feign-service-a调用feign-service-b的接口

    由于我们对feign-service-b启动了两个实例,通过刷新浏览器以及后台打印的日志可以看到Feign通过轮询的方式访问端口为3333或者4444的接口

    下面,我们测试一下Feign的服务降级功能,也就是Feign调用失败后的回调方法,下面我们关掉feign-service-b的两个实例,接着访问http://localhost:2222/getInfo?name=weixiaohuai,如下图

    可以看到,当feign调用失败后,服务调用并没有死掉,而是执行了失败回调方法。

    十二、总结
    Feign的实现的过程大致如下:

    首先通过@EnableFeignCleints注解开启FeignCleint
    根据Feign的规则实现接口,并加@FeignCleint注解
    程序启动后,会进行包扫描,扫描所有的@ FeignCleint的注解的类,并将这些信息注入到ioc容器中。
    当接口的方法被调用,通过jdk的代理,来生成具体的RequesTemplate
    RequesTemplate在生成Request
    Request交给Client去处理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp
    最后Client被封装到LoadBalanceClient类,这个类结合类Ribbon做到了负载均衡
    通过Feign以接口和注解配置的方式,轻松实现了对feign-service-b服务的绑定,这样我们就可以在本地应用中像本地服务一下的调用它,并且做到了客户端均衡负载。

  • 相关阅读:
    sort color (荷兰国旗)
    先序遍历和后序遍历构建二叉树
    二叉树的遍历
    排序
    内存相关内容
    chrome控制台console方法表
    记一次移动端CSS引发的小Bug
    JavaScript的事件
    浅谈webpack打包原理
    JS模块化进程
  • 原文地址:https://www.cnblogs.com/shenyanrushang/p/10852477.html
Copyright © 2011-2022 走看看