声明式服务调用:Spring Cloud Feign

版权声明:本文为博主原创文章,转载需标明出处哦 ^-^。 https://blog.csdn.net/qq_33101675/article/details/88995118

github:https://github.com/Maple521/springcloud/tree/master/feign-consumer

通过前两章对和Spring Cloud Ribbon 和  Spring Cloud Hystrix 的介绍,我们已经掌握了开发微服务应用时的两个重磅武器,学会了如何在微服务架构中实现客户端负载均衡的服务调用,以及如何通过断路器来保护我们的微服务应用。这两者,将被作为基础工具类框架广泛地应用在各个微服务的实现中,不仅包括我们自身的业务类微服务,也包括一些基础设施类服务(比如网关)。此外,在实践过程中,我们会发现对这两个框架的使用几乎是同时出现的。既然如此,那么是否有更高层次的封装来整合这两个基础工具以简化开发呢?本章我们即将介绍的Spring Cloud Feign,就是这样一个工具。它基于Netflix Feign,整合Spring Cloud Ribbon 和  Spring Cloud Hystrix,除了提供这两个强大的功能之外,它还提供了一种声明式的Web服务客户端的定义方式。

我们在使用Spring Cloud Ribbon时,通常都会利用他对RestTemplate的请求拦截,来实现对依赖服务的接口调用,RestTemplate已经实现了对HTTP请求的封装处理,形成了一套模板化的调用方法,在之前的例子中,我们只是简单介绍了调用的实现,但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以我们通常都会针对各个微服务,自行封装一些客户端类,来包装这些依赖服务的调用,这个时候我们会发现,由于RestTemplate的封装,几乎每一个调用都是简单的模板化内容。综合上述这些情况,Spring Cloud Feign在此基础上做了一进一步封装,由它来帮助我们定义和实现依赖服务接口的定义。在Spring Cloud Feign的实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定,简化了在使用Spring Cloud Ribbon时自行封装服务调用客户端的开发量。Spring Cloud Feign具备插拔的注解支持,包括Feign注解和JAX-RS注解。同时,为了适应Spring广大用户,它在Netflix Feign的基础上扩展了对SpringMVC的注解支持。这对于习惯于SpringMVC的开发者来说,无疑是一个好消息,因为这样可以大大减少学习使用它的成本。另外对于Feign自身的一些主要组件,比如编码器和解码器等,他也以可插拔的方式提供,在有需求的时候我们可以方便的扩展和替换他们。

下面的示例将继续使用之前我们实现的hello-service服务,这里我们会通过Spring Cloud Feign提供的声明式服务绑定功能来实现对该服务接口的调用。

(1)首先,创建一个Spring Boot基础工程,取名为 feign-consumer,pom文件为:

<?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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.feign</groupId>
    <artifactId>feign-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>feign-consumer</name>
    <description>Demo project for Feign Consumer</description>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Brixton.SR5</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>

(2)创建应用主类FeignConsumerApplication,并通过@EnableFeignClients注解开启Spring Cloud Feign的支持功能。

package com.feign.feignconsumer;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class FeignConsumerApplication {

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

}

(3)定义HelloService接口,通过@FeignClient注解指定服务名来绑定服务,然后再使用Spring MVC的注解来绑定具体该服务提供的REST接口。

package com.feign.feignconsumer.service;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;

@FeignClient("hello-service")
public interface HelloService {

    @RequestMapping("/hello")
    String hello();
}

注意:这里服务名不区分大小写,所以使用hello-service和HELLO-SERVICE都是可以的。另外,在Brixton.SR5版本中,原有的serviceId属性已经被废弃,若要写属性名,可以使用name或value。

(4)接着,创建一个ConsumerController来实现 对Feign客户端的调用。使用@Autowired直接注入上面定义的HelloService实例,并在helloConsumer函数中调用这个绑定了hello-service服务接口的客户端来向该服务发起 /hello 接口的调用。

package com.feign.feignconsumer.controller;

import com.feign.feignconsumer.service.HelloService;
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.RestController;

@RestController
public class ConsumerController {

    @Autowired
    HelloService helloService;

    @RequestMapping(value = "/feign-consumer", method = RequestMethod.GET)
    public String helloConsumer() {
        return helloService.hello();
    }
}

(5)最后,同Ribbon实现的服务消费者一样,需要 在application.properties中指定服务注册中心,并定义自身的服务名为 feign-consumer,为了方便本地调试与之前的Ribbon消费者区分,端口使用9001.

spring.application.name=feign-consumer
server.port=9001

eureka.client.serviceUrl.defaultZone=http://localhost:1111/eureka/

测试验证

如之前验证Ribbon客户端负载均衡一样,我们先启动服务注册中心以及两个HELLO-SERVICE,然后启动FEIGN-CONSUMER,此时我们在Eureka信息面板中可看到如下内容:

发送几次GET请求道http://localhost:9001/feign-consumer,可以得到如之前Ribbon实现时一样的效果:超过1000ms时,报错。

 时间在1000ms之内呢,返回Hello World

并且根据控制台的输出,我们可以看到Feign实现的消费者,依然是利用了Ribbon维护了针对HELLO-SERVICE的服务列表信息,并且通过轮询实现了客户端负载均衡。而与Ribbon不同的是,通过Feign我们只需定义服务绑定接口,以声明式的方法,优雅而简单地实现了服务调用。我们看下Feign控制台打印情况:

DynamicServerListLoadBalancer for client hello-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=hello-service,current list of Servers=[192.168.0.103:8081, 192.168.0.103:8082],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:2;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:192.168.0.103:8081;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
, [Server:192.168.0.103:8082;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@7fff989d

是不是很面熟呢.....和 ribbon-consumer这里是一样的。

猜你喜欢

转载自blog.csdn.net/qq_33101675/article/details/88995118