feign的RequestMapping之误解

问题背景

在实际生产环境,服务A通过feign调用服务Consumer,FeignClient配置如下

@FeignClient(value = "sleuthConsumer2" , fallbackFactory = Consumer2Factory.class)
public interface Consumer2Client {


    @RequestMapping("/consumer2")
    String  consumer2();

}

一眼看上去这个配置没有任何问题,在实际调用中也可以正常调用,一切都很OK的,直到有一天,由于网络原因, 服务A调用Consumer的consumer2方法操作了了两次。

这个很尴尬了。

问题分析

feign的重试机制和ribbon的重试机制,之前有了解过,feign默认重试五次,但是没有开启的,ribbon默认重试一次,是开启的,这个重试机制也是分场景的,

之前有开过一篇文章讲解过,大家可以去看看feign和ribbon的重试机制 , 我们值得只有GET请求在默认情况下不管啥情况,只要出现网络异常,比如请求超时,都是会进行重试的, 然后我们发现上面的代码并没有指定请求方式,feign默认不会直接给我当做GET请求去做了呢?

代码调试

feign容器启动的时候,对于每个feignClient都会生成一个代理对象,我们直接找到这个代理对象的代码,查看他请求的发起过程,

代码入口: feign.SynchronousMethodHandler

这里写图片描述

这里写图片描述

从上面的调试图上,可以看到,由于我们没有指定请求的方式,feign在构建RequestTemplate的时候读取到的配置,默认就是直接使用了GET请求。

源码解析

此处的源码不会贴的很详细,仅贴的大概

//feign.ReflectiveFeign
public <T> T newInstance(Target<T> target) {
    Map<String, MethodHandler> nameToHandler = targetToHandlersByName.apply(target);
    // 省略代码。。。
    return proxy;
  }

解析target

// 
public Map<String, MethodHandler> apply(Target key) {
      // 主要看这一行代码,解析FeignClient上面的Metadata信息
      List<MethodMetadata> metadata = contract.parseAndValidatateMetadata(key.type());
      Map<String, MethodHandler> result = new LinkedHashMap<String, MethodHandler>();
      for (MethodMetadata md : metadata) {
        // 省略代码。。。
      }
      return result;
    }

下面的调用链就比较深了,我就不一一贴了有兴趣的可以自己去看看

Contract > BaseContract > SpringMvcContract

// org.springframework.cloud.netflix.feign.support.SpringMvcContract
protected void processAnnotationOnMethod(MethodMetadata data,
            Annotation methodAnnotation, Method method) {
        if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation
                .annotationType().isAnnotationPresent(RequestMapping.class)) {
            return;
        }
        // 获取方法上面的RequestMapping注解
        RequestMapping methodMapping = findMergedAnnotation(method, RequestMapping.class);
        // 获取设置的请求方式
        RequestMethod[] methods = methodMapping.method();
        if (methods.length == 0) { // 如果为空,那么直接设置为GET请求
            methods = new RequestMethod[] { RequestMethod.GET };
        }
        //省略代码。。。。

}

总结

在实际的项目当中,使用RequestMapping用作方法上面的映射时,一定要指定 请求方式,或者直接使用PostMapping或者GetMapping之类的,否则出了啥问题,真是一脸懵逼

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u012394095/article/details/82180576