SpringBoot脱离SpringCloud使用Feign

快速导航

添加依赖

Maven

Feign 声明式http请求调用轻量级框架

在项目的 pom.xml 的 dependencies 中加入以下内容:

<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-core</artifactId>
    <version>9.5.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-slf4j</artifactId>
    <version>9.5.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-hystrix</artifactId>
    <version>9.5.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-jackson</artifactId>
    <version>9.5.1</version>
</dependency>
<dependency>
    <groupId>io.github.openfeign</groupId>
    <artifactId>feign-okhttp</artifactId>
    <version>9.5.1</version>
</dependency>

添加核心配置类

在项目中新增 TestFeignConfig 核心配置类,代码如下:

package com.boot.component.test.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.boot.component.test.client.TestApiFeignClient;
import com.boot.component.test.log.TestApiFeignLogger;

import feign.Feign;
import feign.Logger;
import feign.Request;
import feign.Retryer;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.okhttp.OkHttpClient;

/**
 * @Description: FeignClient的配置类
 * @author Lord
 * @date 2019年12月16日
 */
@Configuration
public class TestFeignConfig {

    /**
     * FeignClient 配置
     * @return
     */
    @Bean
    TestApiFeignClient testApiFeignClient() {
        return Feign.builder()
                .client(new OkHttpClient())
                .logger(new TestApiFeignLogger())
                .logLevel(Logger.Level.FULL)
                .encoder(new JacksonEncoder())
                .decoder(new JacksonDecoder())
                .options(new Request.Options(1000, 3500))
                .retryer(new Retryer.Default(5000, 5000, 3))
                .target(TestApiFeignClient.class, "http://127.0.0.1:8085");
    }
}

添加日志配置类

在项目中新增 TestApiFeignLogger 日志配置类,代码如下:

package com.boot.component.test.log;

import java.io.IOException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import feign.Request;
import feign.Response;

public class TestApiFeignLogger extends feign.Logger {

    private final Logger logger;

    public TestApiFeignLogger() {
        this(feign.Logger.class);
    }

    public TestApiFeignLogger(Class<?> clazz) {
        this(LoggerFactory.getLogger(clazz));
    }

    public TestApiFeignLogger(String name) {
        this(LoggerFactory.getLogger(name));
    }

    TestApiFeignLogger(Logger logger) {
        this.logger = logger;
    }

    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {
        if (logger.isInfoEnabled()) {
            super.logRequest(configKey, logLevel, request);
        }
    }

    @Override
    protected Response logAndRebufferResponse(String configKey, Level logLevel, Response response, long elapsedTime)
            throws IOException {
        if (logger.isInfoEnabled()) {
            return super.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
        }
        return response;
    }

    @Override
    protected void log(String configKey, String format, Object... args) {
        // Not using SLF4J's support for parameterized messages (even though it
        // would be more efficient) because it would
        // require the incoming message formats to be SLF4J-specific.
        if (logger.isInfoEnabled()) {
            logger.info(String.format(methodTag(configKey) + format, args));
        }
    }
}

添加远程调用服务类

在项目中新增 TestApiFeignClient 远程调用服务类,代码如下:

package com.boot.component.test.client;

import java.util.List;
import java.util.Map;

import com.boot.component.test.common.CommonReturnType;
import com.boot.component.test.model.response.AccessTokenOutput;
import com.boot.component.test.model.response.area.AddressOutput;

import feign.Headers;
import feign.QueryMap;
import feign.RequestLine;

/**
 * @Description: feignClient的接口(远程调用服务类)
 * @author Lord
 * @date 2019年12月16日
 */
@Headers("Content-Type:application/x-www-form-urlencoded")
public interface TestApiFeignClient {

    @RequestLine("POST /oauth2/accessToken")
    CommonReturnType<AccessTokenOutput> getAccessToken(@QueryMap Map<String, Object> params);

    @RequestLine("POST /oauth2/refreshToken")
    CommonReturnType<AccessTokenOutput> getRefreshToken(@QueryMap Map<String, Object> params);
}

请求返回的最外层对象

在项目中新增 CommonReturnType<T> 请求返回的最外层对象类,代码如下:

package com.boot.component.jd.common;

import java.io.Serializable;

/**
 * @Description: 请求返回的最外层对象
 * @author Lord
 * @date 2019年12月13日
 */
public class CommonReturnType<T> implements Serializable {

    private static final long serialVersionUID = -8797234859999337279L;

    /** 执行结果成功,还是失败. */
    private Boolean success;

    /** 错误码. */
    private String resultCode;

    /** 提示信息. */
    private String resultMessage;

    private T result;

    public Boolean getSuccess() {
        return success;
    }

    public void setSuccess(Boolean success) {
        this.success = success;
    }

    public String getResultCode() {
        return resultCode;
    }

    public void setResultCode(String resultCode) {
        this.resultCode = resultCode;
    }

    public String getResultMessage() {
        return resultMessage;
    }

    public void setResultMessage(String resultMessage) {
        this.resultMessage = resultMessage;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }

    @Override
    public String toString() {
        return "CommonReturnType [success=" + success + ", resultCode=" + resultCode + ", resultMessage="
                + resultMessage + ", result=" + result + "]";
    }

}

获取AccessToken返回对象

在项目中新增 AccessTokenOutput 获取AccessToken返回对象类,代码如下:

package com.boot.component.test.model.response;

import java.io.Serializable;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

/**
 * @Description: 获取AccessToken返回对象
 * @author Lord
 * @date 2019年12月16日
 */
@JsonIgnoreProperties(ignoreUnknown = true)
public class AccessTokenOutput implements Serializable {

    private static final long serialVersionUID = 388723550621265373L;

    /**
     * 业务id
     */
    private String uid;

    /**
     * 访问令牌,用于业务接口调用。(有效期24小时)
     */
    @JsonProperty("access_token")
    private String accessToken;

    /**
     * 当access_token过期时,用于刷新access_token
     */
    @JsonProperty("refresh_token")
    private String refreshToken;

    /**
     * 当前时间,时间戳格式:1551663377887
     */
    private Long time;

    /**
     * access_token的有效期,单位:秒,有效期24小时
     */
    @JsonProperty("expires_in")
    private Integer expiresIn;

    /**
     * refresh_token的过期时间,毫秒级别,时间戳
     */
    @JsonProperty("refresh_token_expires")
    private Long refreshTokenExpires;

    public String getUid() {
        return uid;
    }

    public void setUid(String uid) {
        this.uid = uid;
    }

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public String getRefreshToken() {
        return refreshToken;
    }

    public void setRefreshToken(String refreshToken) {
        this.refreshToken = refreshToken;
    }

    public Long getTime() {
        return time;
    }

    public void setTime(Long time) {
        this.time = time;
    }

    public Integer getExpiresIn() {
        return expiresIn;
    }

    public void setExpiresIn(Integer expiresIn) {
        this.expiresIn = expiresIn;
    }

    public Long getRefreshTokenExpires() {
        return refreshTokenExpires;
    }

    public void setRefreshTokenExpires(Long refreshTokenExpires) {
        this.refreshTokenExpires = refreshTokenExpires;
    }

}

调用示例

TestController

FeignTestController 测试Feign远程调用

FeignTestController 代码如下:

package com.boot.controller.test;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

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

import com.boot.component.test.client.TestApiFeignClient;
import com.boot.component.test.common.CommonReturnType;
import com.boot.component.test.model.response.AccessTokenOutput;
import com.xiaoleilu.hutool.json.JSONUtil;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping("/feign/test")
public class FeignTestController {

    @Resource
    private TestApiFeignClient testApiFeignClient;

    @GetMapping
    public CommonReturnType<AccessTokenOutput> test() {
        String statDate = LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME);

        log.info("进入Feign远程调用服务测试类,当前时间:[{}]", statDate);

        Map<String, Object> params = new HashMap<>(2);
        params.put("username", "admin");
        params.put("password", "admin123");

        CommonReturnType<AccessTokenOutput> accessTokenResult = testApiFeignClient.getAccessToken(params);
        log.info("[测试] 获取 AccessToken 响应结果:[{}]", JSONUtil.toJsonStr(accessTokenResult));

        return accessTokenResult;
    }

}

参考资料

Spring Cloud Feign设计原理

Feign基础教程

SpringBoot脱离SpringCloud使用Feign

Feign真正正确的使用方法

Spring Cloud通过Feign请求返回值LocalDateTime异常处理

spring-boot 调用第三方接口

Feign 日期格式转换错误

Feign输出Info级别日志

Feign基础入门及特性讲解

禁用feign retryer

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,905评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,140评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,791评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,483评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,476评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,516评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,905评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,560评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,778评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,557评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,635评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,338评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,925评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,898评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,142评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,818评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,347评论 2 342

推荐阅读更多精彩内容