SpringCloud 远程调用——OpenFeign

17 篇文章 0 订阅
5 篇文章 0 订阅

1. 导入依赖

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

2. 开启 openFeign

配置类或者启动类上添加注解,自动扫描已经定义好的 FignClient
@EnableFeignClients({"package1", "package2"})

3. 全局处理

异常、编解码、重试、鉴权等。

@Configuration
@ConditionalOnClass({EnableFeignClients.class})
public class FeignConfiguration {
    public FeignConfiguration() {
    }

    @Bean
    public FeignBasicAuthRequestInterceptor basicAuthRequestInterceptor() {
        return new FeignBasicAuthRequestInterceptor();
    }

    @Bean
    public FeignExceptionAspect feignExceptionAspect() {
        return new FeignExceptionAspect();
    }

    @Bean
    public Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }

    @Bean
    public Decoder feignDecoder() {
        final MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
        simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
        simpleModule.addDeserializer(BigDecimal.class, BigDecimalJsonDeserializer.instance);
        simpleModule.addSerializer(BigDecimal.class, BigDecimal2Serializer.instance);
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(Date.class, new DateSerializer(false, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addDeserializer(Date.class, new DateDeserializer());
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
        objectMapper.registerModule(javaTimeModule);
        objectMapper.registerModule(simpleModule);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        List<MediaType> fastMediaTypes = new ArrayList();
        fastMediaTypes.add(MediaType.ALL);
        jackson2HttpMessageConverter.setSupportedMediaTypes(fastMediaTypes);
        jackson2HttpMessageConverter.setObjectMapper(objectMapper);
        ObjectFactory<HttpMessageConverters> objectFactory = new ObjectFactory<HttpMessageConverters>() {
            public HttpMessageConverters getObject() throws BeansException {
                return new HttpMessageConverters(new HttpMessageConverter[]{jackson2HttpMessageConverter});
            }
        };
        return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
    }
}

4. 关键代码

鉴权:

public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {
    public FeignBasicAuthRequestInterceptor() {
    }

    public void apply(RequestTemplate template) {
       // 1. 通过设置一个永久的 token 来鉴权
        template.header("access-token", "xxxxx");
       // 2. 也可以获取 requestAttributes 放入 header中,当然这个是大家提前约定好
        ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            Enumeration<String> reqAttrbuteNames = request.getAttributeNames();
            if (reqAttrbuteNames != null) {
                while(reqAttrbuteNames.hasMoreElements()) {
                    String attrName = (String)reqAttrbuteNames.nextElement();
                    // isAuthorizationed 是约定好的自定义头,方便内部调用
                    if ("isAuthorizationed".equalsIgnoreCase(attrName)) {
                        Map<String, String> requestHeaderMap = (Map)request.getAttribute(attrName);
                        Iterator var7 = requestHeaderMap.entrySet().iterator();

                        while(var7.hasNext()) {
                            Entry<String, String> entry = (Entry)var7.next();
                            template.header((String)entry.getKey(), new String[]{(String)entry.getValue()});
                        }

                        return;
                    }
                }
            }
        }

    }
}

异常处理:

@Aspect
public class FeignExceptionAspect {

    public FeignExceptionAspect() {
    }

    @Pointcut("@within(org.springframework.cloud.openfeign.FeignClient)")
    public void feignClientPointCut() {
    }

    @Around("feignClientPointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        Object object = proceedingJoinPoint.proceed();
        if (object == null) {
            throw new BusinessException(ResponseCode.FAILED.getCode(), "服务间调用异常,请稍后重试!");
        } else if (object instanceof HttpResult) {
            HttpResult<?> httpResult = (HttpResult)object;
            if (Objects.equals(ResponseCode.SUCCESS.getCode(), httpResult .getCode()) && httpResult .isSuccess()) {
                return object;
            } else {
                throw new BusinessException(ResponseCode.FAILED.getCode(), httpResult .getMsg());
            }
        } else {
            return object;
        }
    }
}

注意:feign 异常处理中并没有捕获被调用方抛出的异常,所以被调用的接口中业务异常不要抛,而是返回一个对象。当然你也可以在这里捕获异常然后处理:

try {  
    Object object = proceedingJoinPoint.proceed();
} catch(BusinessException e) {
    // 将BusinessException 转为HttpResult并返回
}

这样做的好处是,被调用接口既可以被直接调用,也可以被远程内部调用。

5. 使用

可以通过微服务的注册中新和  @EnableDiscoveryClient 注解来自动发现服务:

@FeignClient(value = "userCenter", path = "/userCenter")
public interface InternetusercenterServiceInterface {

    /**
     * 根据ID查询用户信息
     */
    @RequestMapping(value = "/userCenter/getUserInfoById", method = RequestMethod.GET)
    HttpResult<UserInfoVO> getUserInfoById(@RequestParam Long id);

}

本文结束,做任何事情先把整体后局部, 使用 openFeign 步骤是什么,然后每一步去实现他就可以了。


如果觉得还不错的话,关注、分享、在看(关注不失联~), 原创不易,且看且珍惜~

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【非典型Coder】

赏个鸡腿吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值