返回顶部

openfeign的使用

一、项目目录结构

1、craft微服务(服务提供者):

  包含craft-core模块、craft-facade模块;core模块是craft微服务的核心模块,facade是craft微服务对外提供远程调用模块;

 2、order微服务(服务使用者):

包含order-core模块、order-facade模块;core模块是order微服务的核心模块,facade模块是order微服务对外提供远程调用的模块

二、简单使用

添加在各种模块引入openfeign依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <version>2.1.RELEASE</version>
</dependency>

1、服务提供者craft

1.1craft-facade模块创建远程调用接口

package com.atxgl.craft.facade.feignClient;

import com.atxgl.craft.facade.entity.CraftVersionDto;
import com.atxgl.craft.facade.request.CraftVersionRequest;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@Service
@FeignClient(value = "craft-service", fallback = CraftVersionFeignFallback.class)
public interface CraftVersionFeign {

    @GetMapping("/queryOrderCraft")
    List<CraftVersionDto> queryOrderCraft(@SpringQueryMap CraftVersionRequest craftVersionRequest);
}

 2、craft-core模块实现对外提供的接口服务CraftVersionFeign

package com.atxgl.craft.core.contorller;

import com.atxgl.common.exception.BusinessException;
import com.atxgl.craft.facade.entity.CraftVersionDto;
import com.atxgl.craft.facade.feignClient.CraftVersionFeign;
import com.atxgl.craft.facade.request.CraftVersionRequest;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;

import java.util.ArrayList;
import java.util.List;

@RestController
@ApiIgnore
public class CraftVersionFeignController implements CraftVersionFeign {

    @Override
    public List<CraftVersionDto> queryOrderCraft(CraftVersionRequest craftVersionRequest) {
        if ("123".equals(craftVersionRequest.getOrderId())){
            throw new BusinessException(10020, "订单id不能为123");
        }
        ArrayList<CraftVersionDto> craftVersionDtos = new ArrayList<>();
        craftVersionDtos.add(new CraftVersionDto().setId("1212132"));
        return craftVersionDtos;
    }
}

2、服务使用者orde微服务

2.1、引入craft-facade模块的依赖

<dependency>
    <groupId>com.atxgl</groupId>
    <artifactId>craft-facade</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

2.2、在启动类上添加@EnableFeignClients

package com.atxgl.order.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.core.env.Environment;

import java.net.InetAddress;
import java.net.UnknownHostException;

@SpringBootApplication
/**
* 扫描标记了@FeignClient的接口并创建实例bean,默认扫描并创建所在工程下的包,
* 如果要扫描其他路径的包需要在basePackage属性添加路径,
* 注意如果自己包路径下也有,需要加上本工程的
*/
@EnableFeignClients(basePackages = {"com.atxgl.craft.facade.*"}) 
@Slf4j
@EnableDiscoveryClient
@ComponentScan(basePackages
= {"com.atxgl.order.*","com.atxgl.craft.facade.*"})
public class OrderApplication {
  public static void main(String[] args) throws UnknownHostException {
    ConfigurableApplicationContext application
= SpringApplication.run(OrderApplication.class, args);
}
}

2.3、使用@Autowired注解标注CraftVersionFeign参数

package com.atxgl.order.core.service.impl;

import com.atxgl.craft.facade.entity.CraftVersionDto;
import com.atxgl.craft.facade.feignClient.CraftVersionFeign;
import com.atxgl.craft.facade.request.CraftVersionRequest;
import com.atxgl.order.core.service.OrderCraftService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Slf4j
@Service
public class OrderCraftServiceImpl implements OrderCraftService {

    @Autowired
    private CraftVersionFeign craftVersionFeign;

    @Override
    public List<CraftVersionDto> queryCraftVersion(String orderId) {
        CraftVersionRequest craftVersionRequest = new CraftVersionRequest();
        craftVersionRequest.setOrderId(orderId);
        List<CraftVersionDto> craftVersionDtos = craftVersionFeign.queryOrderCraft(craftVersionRequest);
        log.info("result---" + craftVersionDtos.toString());
        return craftVersionDtos;
    }
}

 三、扩展

1、feign拦截器RequestInterceptor

使用feign在服务间调用时,可以实现RequestInterceptor接口的apply方法,对请求进行处理

package com.atxgl.common.feign;

import com.atxgl.common.base.ResponseEnum;
import com.atxgl.common.context.request.RequestContext;
import com.atxgl.common.exception.BaseException;
import feign.RequestInterceptor;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @program: springCloud230416
 * @description: feign拦截器:
 *  在调用feign接口请求的时候进行拦截,实现对请求进行处理
 * @author: xiaogl
 * @create: 2023-04-20 17:17
 */
@Configuration
@Slf4j
public class FeignClientInterceptorConfig implements RequestInterceptor {


    @Override
    public void apply(RequestTemplate requestTemplate) {

        ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String requestId =  request.getHeader("requestId");

        log.info("requestId:{}", requestId);
        if (!StringUtils.hasLength(requestId)){
            throw new BaseException(ResponseEnum.REQUEST_ID_NOT_EMPTY);
        }else {
            requestTemplate.header(RequestContext.REQUEST_ID, requestId);
        }

        requestTemplate.header(RequestContext.REQUEST_ID, requestId);
    }
}

2、自定义feign异常解析器ErrorDecoder

  feign默认的错误处理程序ErrorDecode.default总是抛出FeignException,我们可以通过实现ErrorDecode接口的decode方法自定义异常返回信息

package com.atxgl.common.feign;


import com.alibaba.fastjson.JSON;
import com.atxgl.common.base.ResponseEnum;
import com.atxgl.common.base.Result;
import com.atxgl.common.exception.BaseException;
import com.atxgl.common.exception.BusinessException;
import com.atxgl.common.exception.ParameterValidException;
import feign.Response;
import feign.Util;
import feign.codec.ErrorDecoder;
import lombok.extern.slf4j.Slf4j;

/**
 * 自定义openfeign客户端接收请求返回异常信息
 */
@Slf4j
public class FeignClientErrorDecoder implements ErrorDecoder {


    @Override
    public Exception decode(String s, Response response) {
        try {
            String s1 = Util.toString(response.body().asReader());
            log.info("执行了FeignClientErrorDecoder:{}", s1 );
            Result result = JSON.parseObject(s1, Result.class);
            if (BaseException.STATUS.equals(response.status())){
                return new BaseException(result.getCode(), result.getMessage());

            } else if (BusinessException.STATUS.equals(response.status())) {
                return new BusinessException(result.getCode(), result.getMessage());

            }else if (ParameterValidException.STATUS.equals(response.status())) {
                return new ParameterValidException(result.getCode(), result.getMessage());
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return new BaseException(ResponseEnum.INVALID_PARAM_ERROR);
    }
}

3、容错机制

  开启feign对熔断器的支持,在配置文件添加feign.hystrix.enabled=true

  • 使用fallback属性
  • 使用fallbackFactory属性

3.1 fallback属性

  在对接口使用@FeignClient声明feign客户端后,可以使用属性fallback指定异常处理类,这个类必须实现@FeignClinet作用的接口,且被注入到容器中;

@Service
@FeignClient(value = "craft-service", fallback = CraftVersionFeignFallback.class)
public interface CraftVersionFeign {

    @GetMapping("/queryOrderCraft")
    List<CraftVersionDto> queryOrderCraft(@SpringQueryMap CraftVersionRequest craftVersionRequest);
}

@Component
@Slf4j
public class CraftVersionFeignFallback implements CraftVersionFeign{
    @Override
    public List<CraftVersionDto> queryOrderCraft(CraftVersionRequest craftVersionRequest) {
        log.info("执行了CraftVersionFeignFallback");
        return new ArrayList<>();
    }
}

3.2 fallbackFactory属性

  在对接口使用@FeignClient声明feign客户端后,可以使用属性fallbackFactory指定异常处理类,这个类必须实现FallbackFactory接口,且被注入到容器中;

@Service
@FeignClient(value = "craft-service", fallbackFactory = CraftVersionFeignFallbackFactory.class)
public interface CraftVersionFeign {

    @GetMapping("/queryOrderCraft")
    List<CraftVersionDto> queryOrderCraft(@SpringQueryMap CraftVersionRequest craftVersionRequest);
}


@Slf4j
@Component
public class CraftVersionFeignFallbackFactory implements FallbackFactory<CraftVersionFeign> {
    @Override
    public CraftVersionFeign create(Throwable cause) {
        log.error("CraftVersionFeign远程调用错误:{}", cause.getMessage());
        return new CraftVersionFeign() {
            @Override
            public List<CraftVersionDto> queryOrderCraft(CraftVersionRequest craftVersionRequest) {
                return new ArrayList<CraftVersionDto>();
            }
        };
    }
}

 

posted @ 2023-04-25 21:20  一只小缘  阅读(135)  评论(0)    收藏  举报