Feign 配置使用

简介:feign是springcloud的一个重要组件,主要功能就是服务调用,既可以用于微服务之间调用,也可以rest调用
 

启用

pom文件 添加依赖

<!-- Feign 远程服务调用依赖-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>

启动类上添加注解 @EnableFeignClients

在这里插入图片描述
 

微服务调用

目标:调用微服务里用户服务的获取用户信息接口
步骤:

  • 新建一个 interface 接口类
  • 注解上填写接口的url
  • 方法的写法类似于controller
  • 配置 application

IUserService 接口

import com.njc.java.entity.base.ResponseEntity;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@FeignClient(value = "user-service", url = "${api.user}")
public interface IUserService {

    @RequestMapping(value = "/user/info", method = RequestMethod.GET)
    ResponseEntity<RespDTO> getUserInfo();

}

application.yml

api:
  user: user-service:8888

rest 调用类似,把 application.yml 修改 url 即可

api:
  user: http://192.168.188.1:8888

 

传参

Header传参

KEYVALUE
AuthorizationTOKEN
@RequestMapping(value = "/user", method = RequestMethod.GET)
ResponseEntity<RespDTO> userInfo(@RequestHeader(name = "Authorization") String token);

 

URL传参

@RequestMapping(value = "/user/{pernr}", method = RequestMethod.GET)
NjcResponseEntity<UserInfoRespDTO> userInfo( @PathVariable("pernr") String pernr);

 

Params传参

@GetMapping(value = "/user")
NjcResponseEntity<String> userInfo(@SpringQueryMap ReqDTO reqDTO);

 

Body传参

@GetMapping(value = "/user")
NjcResponseEntity<String> userInfo(@RequestBody ReqDTO reqDTO);

 

统一传参

场景举例:IUserService 在调用时,所有接口都需要在 Header 加 token

  • 配置 configuration 实现 RequestInterceptor
import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;

public class FeignConfig implements RequestInterceptor {

    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        
        //添加token
        requestTemplate.header("Authorization", request.getHeader("Authorization"));
    }
}
  • 接口添加 configuration
@FeignClient(url = "${api.user.url}", name = "user-service", configuration = FeignConfig.class)
public interface IUserService {

    @GetMapping(value = "/user/user/{userId}")
    ResponseEntity<UserSimpleInfoRespDTO> getUserInfo(@PathVariable(value = "userId") Long userId);

}

 

日志打印

设置 config

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

@Configuration
public class FeignConfig {

    @Bean
    public Logger.Level feignLogLevel(){
        /* 设置feign客户端的日志打印级别为FULL */
        return Logger.Level.BASIC;
    }

    @Bean
    Logger feignLogger() {
        return new NjcFeignLogger();
    }
}
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import feign.*;
import feign.Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.io.*;
import java.util.*;
import static feign.Util.decodeOrDefault;
import static java.nio.charset.StandardCharsets.UTF_8;

/**
 * Feign请求日志处理类<br/>
 * 所有通过Feign请求的外部接口都会被监控
 */
@Slf4j
public class NjcFeignLogger extends Logger {

    private static final ThreadLocal<Map<String, String>> logContext = new ThreadLocal<>();

    private static final String PATH = "path";

    private static final String METHOD = "method";

    private static final String REQUEST_BODY = "body";

    private static final String HEADER = "header";

    private static final String TIME = "time";

    /**
     * 构建headers字符串
     */
    private String builderHeaders(Map<String, Collection<String>> headersMap) {
        StringBuilder headers = new StringBuilder();
        Iterator<Map.Entry<String, Collection<String>>> iterator = headersMap.entrySet().stream().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Collection<String>> next = iterator.next();
            ArrayList<String> values = new ArrayList<>(next.getValue());
            headers.append(next.getKey())
                    .append(":")
                    .append(values.size() == 1 ? values.get(0) : JSON.toJSONString(values))
                    .append(iterator.hasNext() ? "|" : "");
        }
        return headers.toString();
    }

    /**
     * 请求拦截
     */
    @Override
    protected void logRequest(String configKey, Level logLevel, Request request) {
        Map<String, String> map = new HashMap<>(3);
        map.put(PATH, request.url());
        map.put(TIME, System.currentTimeMillis() + "");
        map.put(METHOD, request.httpMethod().name());
        map.put(HEADER, builderHeaders(request.headers()));
        String body = request.body() == null ? null : request.charset() == null ? null : new String(request.body(), request.charset());
        //文件上传不打印请求日志
        if (StringUtils.contains(request.url(), "/helper/common/file/upload")) {
            body = null;
        }
        map.put(REQUEST_BODY, body);
        logContext.set(map);
    }


    /**
     * 响应拦截
     */
    @Override
    protected feign.Response logAndRebufferResponse(
            String configKey, Level logLevel, Response response, long elapsedTime) throws IOException {
        Map<String, String> request = logContext.get();
        logContext.remove();
        // 返回参数
        byte[] bodyData = streamToByteArray(response.body().asInputStream());
        if (null != bodyData && bodyData.length > 0) {
            String responseBody = decodeOrDefault(bodyData, UTF_8, "Binary data");
            log(request, response.status(), responseBody.replaceAll("\\s*|\t|\r|\n", ""));
            return response.toBuilder().body(bodyData).build();
        }
        log(request, response.status(), null);
        return response;
    }

    /**
     * 异常拦截
     */
    @Override
    protected IOException logIOException(String configKey, Level logLevel, IOException ioe, long elapsedTime) {
        Map<String, String> request = logContext.get();
        log.info("Feign-Error -> \npath -> {}\nmethod -> {}\nheaders -> {}\nrequest -> {}\n",
                request.get(PATH), request.get(METHOD), request.get(HEADER), request.get(REQUEST_BODY)
        );
        logContext.remove();
        return ioe;
    }

    /**
     * 日志打印
     *
     * @param request
     * @param responseStatus
     * @param responseBody
     */
    private void log(Map<String, String> request, Integer responseStatus, String responseBody) {
        log.info("\n<Feign>" +
                        "\npath     -> {}" +
                        "\ntime     -> {}" +
                        "\nmethod   -> {}" +
                        "\nstatus   -> {}" +
                        "\nheaders  -> {}" +
                        "\nrequest  -> {}" +
                        "\nresponse -> {}",
                request.get(PATH),
                (System.currentTimeMillis() - Long.parseLong(request.get(TIME))) + "ms",
                request.get(METHOD),
                responseStatus,
                request.get(HEADER),
                request.get(REQUEST_BODY),
                responseBody
        );
    }

    @Override
    protected void log(String configKey, String format, Object... args) {
        if (log.isInfoEnabled()) {
            log.info(String.format(methodTag(configKey) + format, args));
        }
    }



    /**
     * 输入流转byte[]
     *
     * @param inStream 文件流内容
     * @return
     */
    public static byte[] streamToByteArray(InputStream inStream) {
        if (inStream == null) {
            return null;
        }
        byte[] in2b = null;
        BufferedInputStream in = new BufferedInputStream(inStream);
        ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
        int rc = 0;
        try {
            while ((rc = in.read()) != -1) {
                swapStream.write(rc);
            }
            in2b = swapStream.toByteArray();
        } catch (IOException e) {
            log.warn("streamToByteArray exception inStream:[{}]", inStream, e);
        } finally {
            closeIo(inStream, in, swapStream);
        }
        return in2b;
    }


    /**
     * 关闭流
     */
    public static void closeIo(Closeable... closeable) {
        if (null == closeable || closeable.length <= 0) {
            return;
        }
        for (Closeable cb : closeable) {
            try {
                if (null == cb) {
                    continue;
                }
                cb.close();
            } catch (IOException e) {
                throw new RuntimeException(
                        FileUtil.class.getName(), e);
            }
        }
    }
}

打印结果如下
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用Feign进行服务之间的调用时,可以通过配置开启Hystrix的熔断功能。如果服务不可用或者超过访问时间,就会触发Hystrix的fallback回调函数。要开启熔断配置,需要在服务消费者的pom文件中添加Hystrix的依赖。然后创建Feign的实现类,实现Feign中的方法,并在Feign接口的@FeignClient注解中加上fallback属性,值是Feign实现类的字节码文件。在主启动类上加上@EnableHystrix注解来允许Hystrix的使用。在配置文件中设置开启熔断功能,可以通过feign.hystrix.enabled=true来开启Feign的熔断功能。\[1\] Feign中的Hystrix配置如下: ``` feign: hystrix: enabled: true okhttp: enabled: true httpclient: enabled: false client: config: default: # 超时时间配置 connectTimeout: 10000 readTimeout: 10000 compression: request: enabled: true response: enabled: true # Hystrix配置 hystrix: command: default: execution: isolation: strategy: SEMAPHORE thread: timeoutInMilliseconds: 60000 shareSecurityContext: true ``` 以上是Feign中Hystrix的配置,可以根据实际需求进行相应的调整。\[3\] #### 引用[.reference_title] - *1* *3* [Spring Cloud Feign熔断配置](https://blog.csdn.net/Diandikongji/article/details/112747687)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [feign的熔断](https://blog.csdn.net/weixin_45893072/article/details/122972939)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值