Feign配合Ribbon和Eureka来提供负载均衡的HTTP客户端(四)

1.1         Feigh

1.1.1      概念

Feign is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka to provide a load balanced http client when using Feign.

Feigh是一个声明式web服务客户端。它能让开发web服务变得容易。使用Feign需要创建一个接口并注解它。它拥有包括Feign注解和JAX-RS注解的可插拔支持。它还支持可插拔的编码器和解码器。Spring Cloud拥有Spring MVC支持,并使用Spring Web中默认同样的HttpMessageConverters。在使用Feign时,Spring Cloud集成了RibbonEureka来提供负载均衡的HTTP客户端。

总结:Feign简化HttpClient开发,封装了JAX-RSspringmvc的注解,学习成本很低。

1.1.2      Feign的坑

不能直接支持接收对象参数,只能一个一个属性接收。如果必须要接收对象参数,可以变相通过@RequestBody,通过json的表单提交来实现。

对于日期类型支持和json转换间冲突多,还滞后8小时。转为字符串类型,在提供者时,再强制转换为日期,更加方便些。

1.2         消费者实现Feign

1.2.1      创建Maven工程

1.2.2      pom.xml

<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>cn.tedu</groupId>

    <artifactId>consumer-feign</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.5.4.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>

    </properties>

    <dependencies>

        <!-- HystrixFeign是基于Hystrix -->

        <dependency>

             <groupId>org.springframework.cloud</groupId>

             <artifactId>spring-cloud-starter-hystrix</artifactId>

        </dependency>

        <!-- 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>

        <dependency>

             <groupId>org.springframework.boot</groupId>

             <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

    </dependencies>

    <dependencyManagement>

        <dependencies>

             <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-dependencies</artifactId>

                 <version>Dalston.SR1</version>

                 <type>pom</type>

                 <scope>import</scope>

             </dependency>

        </dependencies>

    </dependencyManagement>

</project>

1.2.3      application.yml

server:

  port: 9001

spring:

  application:

    name: consumer-feign

eureka:

  client:

    serviceUrl:

      defaultZone: http://user:password123@localhost:8761/eureka

1.2.4      EurekaServiceFeign.java

以接口对外暴露,从而封装底层操作。

package cn.tedu.client;

import org.springframework.cloud.netflix.feign.FeignClient;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RequestMethod;

// 这个接口相当于把原来的服务提供者项目当成一个Service

@FeignClient(value="provider-user")

public interface EurekaServiceFeign {

    /*

     * Feign中没有原生的@GetMapping/@PostMapping/@DeleteMapping/@PutMapping,要指定需要用method进行

     */

    @RequestMapping(value="/hello/{name}",method=RequestMethod.GET)

    public String hello(@PathVariable("name") String name);

}

1.2.5      HelloController.java

package cn.tedu.controller;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.PathVariable;

import org.springframework.web.bind.annotation.ResponseBody;

import org.springframework.web.bind.annotation.RestController;

import cn.tedu.client.EurekaServiceFeign;

@RestController

public class HelloController {

    @Autowired

    private EurekaServiceFeign eurekaServiceFeign;

   

    @GetMapping("/hello/{name}")

    @ResponseBody

    public String hello(@PathVariable String name){

        return eurekaServiceFeign.hello(name);

    }

}

1.2.6      FeignRunApp.java

package cn.tedu;

import org.springframework.boot.SpringApplication;

import org.springframework.cloud.client.SpringCloudApplication;

import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringCloudApplication

@EnableFeignClients          //开启Feign

public class FeignRunApp {

    public static void main(String[] args) {

        SpringApplication.run(FeignRunApp.class, args);

    }

}

1.2.7      常见的坑

只支持旧的@RequestMapping不支持新的@GetMapping()

method=RequestMethod.GET 只支持POST方法,GET方法也会自动转到POST方法

@PathVariable("name") String name 必须写名称“name”,springmvc可以不写

启动超过1s会报超时,再刷新就可以正常访问,原因在于hystrix断路器的影响,稍差的机器就会发生。

1.2.8      测试

执行顺序:

先启动服务端 8761    eureka-server        EurekaServerApp

在启动提供者1   7900    provider-user        ProviderRunApp

最后启动消费者   9001    consumer-client  ConsumerRunApp

访问Eureka控制台:      http://localhost:8761/

访问请求:               http://localhost:9001/hello/hellen

出现1:hellen,页面出现,设置断点,发现提供者也进入了,Feign消费者也进入了。

1.3         拓展:Feign实现降级

1.3.1      CartFeignFallback

直接实现消费者的CartFeign接口,给每个方法设置异常时的处理

package cn.jt.feign;

import org.springframework.stereotype.Component;

import cn.jt.common.vo.SysResult;

import cn.jt.pojo.Cart;

@Component   //微服务访问异常则启用降级

public class CartFeignFallback implements CartFeign{

    @Override

    public SysResult mycart(Long userId) {

        return SysResult.build(400, "mycart error.");

    }

    @Override

    public SysResult save(Cart cart) {

        return SysResult.build(400, "save error.");

    }

    @Override

    public SysResult update(Cart cart) {

        return SysResult.build(400, "update error.");

    }

    @Override

    public SysResult delete(Cart cart) {

        return SysResult.build(400, "delete error.");

    }

}

1.3.2      修改接口CartFeign

@FeignClient(value="jt-cart-provider",fallback = CartFeignFallback.class)

public interface CartFeign {

1.3.3      application.yml

server:

  port: 9001

spring:

  application:

    name: jt-cart

eureka:

  client:

    serviceUrl:

      defaultZone: http://user:password123@localhost:8761/eureka

#feign集成hystrix必须开启

feign:

  hystrix:

    enabled: true

   

logging:

  level:

    root: INFO

1.4         Feign小结

1.4.1      调用过程

首先,提供者provider-user和消费者custorm-feign都注册到Eureka中。用户请求feign中的controllerfeign中的controller调用feign定义的接口方法。接口的方法根据注解去找到eureka注册中心中的provider-user地址,然后请求远程provider-user所在服务器的地址,然后调用远程的provider-user提供者的具体服务。提供者响应返回jsonjsonfeign封装传输给“接口”的返回值,“接口”在返回给feigncontroller,最终响应给用户。

1.4.2      自动创建实现类

Feign是典型的基于接口,基于动态代理技术自动生成代理对象。

设置断点,可以清晰的看到这个过程。先访问consumer-feigncontroller;观察EurekaServiceFeign接口,如下图其实一个jdk动态代理类。

动态代理类根据配置的注解信息去Eureka中找到对应调用的提供者的链接信息,进行访问,断点就进入到provider-usercontroller中具体执行,执行完成层层返回。

猜你喜欢

转载自www.cnblogs.com/wood-life/p/10332919.html
今日推荐