feign远程调用的使用

Feign

feign的介绍

feign的是一个http请求调用轻量级的框架,可以使Java接口注解的方式调用Http请求。Feign通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。Feign支持多种注解,例如Feign自带的注解或者JAX­RS注解等。Spring Cloud对Feign进行了增强,使其支持Spring MVC注解,另外还整合了Ribbon和Eureka,从而使得Feign的使用更加方便.
* 此文档主要围绕以下图片开展

feign远程调用的使用_第1张图片

feign源码解析

自动装配

先看一下feign的自动装配,看一下spring.factories中有哪些自动装配类feign远程调用的使用_第2张图片
其中最主要的就是FeignRibbonClientAutoConfigurationFeignHalAutoConfiguration
1.FeignRibbonClientAutoConfiguration,看类名可以发现跟ribbon的负载均衡有关,feign默认使用ribbon作为负载均衡器

客户端

准备

1、依赖

<dependencies>
        <!--feign依赖-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!--支持 HTTP 协议的客户端编程工具包-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
        </dependency>
        <!--fluent-hc用于构建http请求-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>fluent-hc</artifactId>
        </dependency>
    </dependencies>

 <!--cloud的版本配置-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR9</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.6.7</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>

    </dependencyManagement>

2、配置文件application.properties

#配置端口
server.port=9999
# spring开启允许循环依赖
spring.main.allow-circular-references=true
#日志的级别
logging.level.cn.ton.controller.feign.DemoFeign = debug

3.在启动类添加注解

@EnableFeignClients

4、设置日志打印级别

日志的级别有以下四种

feign远程调用的使用_第3张图片

设置日志有两种方式

1、配置文件
2、实体类

扩展 :日志的级别分类

共有八个级别,从低到高为:ALL< TRACE< DEBUG< INFO< WARN < ERROR < FATAL

日志级别的设置
1.使用实体类的方式设置日志级别

第一步:自定义一个FeignConfig配置类

**
 * 这个类上千万不要添加@Configuration,不然会被作为全局配置文件共享 *
 */
class FeignConfig {
    @Bean
    public Logger.Level level() {
        return Logger.Level.FULL;
    }
}

第二部:在feignClient上指定configuration

@FeignClient(nurl = "localhost:8080",name = "FeignDemo1" , configuration = FeignConfig.class)
public interface DemoFeign {
    @GetMapping(value = "/get" ,produces = "application/json; charset=utf-8" ,consumes = "application/json; charset=utf-8")
    String get();

}

第三步:设置配置文件,启动调试模式
这里如果不开启,所有日志都不会被打印出来,也就是相当于日志的开关,这里设置了,上面的自定义日志级别才能生效

logging.level.cn.ton.controller.feign.DemoFeign = debug
2.使用配置文件的方式设置日志级别

在调用方 通过feign:client:config:微服务名称:loggerLevel: 日志级别来指定

feign.client.config.DemoFeign.loggerLevel:HEADERS

客户端1

1、说明

添加了@FeignClient注解的接口为使用feign进行远程调用的客户端

@FeignClient( url = "localhost:8080",name = "FeignDemo1" ,path = "/student",contextId = "客户端id",fallbackFactory = DemoFeignImpl.class,configuration = DemoFeignConfig.class)

@FeignClient 注解说明:
url:要远程调用的服务的地址
name/value:客户端/服务端的名字(若配置Nacos/Eureka服务的注册一起使用,此处配置的nane/value会与其服务地址映射)
path:给客户端添加一个通用的路径
context:客户端的id
fallbackFactory:设置的回退处理类
configuration:私有配置类

代码

package cn.ton.controller.feign;
import cn.ton.common.config.DemoFeignConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;

@FeignClient( url = "localhost:8080/student",name = "123213" ,fallbackFactory = DemoFeignImpl.class,configuration = DemoFeignConfig.class)
public interface DemoFeign {
	/*@PostMapping中说明
    * produces:指定返回值类型
    * consumes:指定处理请求当中的提交内容类型(Content-Type)
    * */
    @PostMapping(value = "/post",produces = "application/json; charset=utf-8",consumes = "application/json; charset=utf-8")
    String postDemo(@RequestBody String a);

    @GetMapping(value = "/get" ,produces = "application/json; charset=utf-8" ,consumes = "application/json; charset=utf-8")
    String getDemo();
}

全局配置类(被@Configuration注解的类)

加有@Configuration注解的类为全局配置类(若不设置配置类,feign会默认创建)可根据需求自定义编解码,错误处理,日志,拦截器等的配置。

package cn.ton.common.config;

import feign.*;
import feign.codec.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.io.IOException;
import java.lang.reflect.Type;

import static java.lang.String.format;

@Configuration
public class FeignConfig {
    /**
     * Feign 的日志打印设置
     * @return
     */
    @Bean
    public Logger.Level log(){
        return Logger.Level.FULL;
    }

    /**
     * 编码
     * @return
     */
    @Bean
    public Encoder encoder(){

        return new Encoder() {
            @Override
            public void encode(Object object, Type bodyType, RequestTemplate template) throws EncodeException {
                if (bodyType == String.class) {
                    template.body(object.toString());
                } else if (bodyType == byte[].class) {
                    template.body((byte[]) object, null);
                } else if (object != null) {
                    throw new EncodeException(
                            format("%s is not a type supported by this encoder.", object.getClass()));
                }
            }
        };

    }

    /**
     * 解码
     * @return
     */
    @Bean
    public Decoder decoder(){
        return new Decoder() {
            @Override
            public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
                if (response.status() == 404 || response.status() == 204)
                    return Util.emptyValueOf(type);
                if (response.body() == null)
                    return null;
                if (byte[].class.equals(type)) {
                    return Util.toByteArray(response.body().asInputStream());
                }
                return null;
            }
        };
    }

    /**
     * 错误处理
     * @return
     */
    @Bean
    public ErrorDecoder errorDecoder(){
        return new ErrorDecoder() {
            @Override
            public Exception decode(String methodKey, Response response) {

                System.out.println("方法名?"+methodKey);
                if (response.status() != 200) {
                    return new RuntimeException("不正常的请求"+response.status());
                }
                return null;
            }
        };
    }

/**
     * 自定义拦截器
     */
    @Bean
    public RequestInterceptor getRequestInterceptor() {
        return new RequestInterceptor(){

            @Override
            public void apply(RequestTemplate template) {
                //设置拦截器内容
            }
        };
    }

}

私有配置类

私有配置类为@FeignClient注解中configuration="XXX.class"参数所指定的类

package cn.ton.common.config;

import feign.Response;
import feign.codec.ErrorDecoder;
import org.springframework.context.annotation.Bean;

public class DemoFeignConfig {


    @Bean
    public ErrorDecoder errorDecoder(){
        return new ErrorDecoder() {
            @Override
            public Exception decode(String methodKey, Response response) {

                System.out.println("方法名?"+methodKey);
                if (response.status() != 200) {
                    return new RuntimeException("不正常的请求"+response.status());
                }


                return null;
            }
        };
    }
}



回退处理

私有配置类为@FeignClient注解中fallbackFactory="XXX.class"参数所指定的类

package cn.ton.controller.feign;

import feign.hystrix.FallbackFactory;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DemoFeignImpl implements FallbackFactory<DemoFeign> {

    @Override
    public DemoFeign create(Throwable throwable) {
        return new DemoFeign() {
            @Override
            public String postDemo(String a) {
                return null;
            }

            @Override
            public String getDemo() {
                return "出错了,但是我有应对策略 返回一个默认的字符串 ...";
            }
        };
    }
}

服务端(第三方服务)

请求接口

新建一个新项目,准备一个controller层

此项目使用默认的8080端口

package cn.ton.controller;

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

@RequestMapping("/student")
@RestController
public class Student {
    @PostMapping("/post")
    public String post(@RequestBody String date){

        return "post请求返回"+date+"数据";
    }

    @GetMapping("/get")
    public String get() {


        return "Get请求返回";
    } 

}

feign底层解析

你可能感兴趣的:(spring,Cloud组件,java,spring,spring,cloud)