代码先行
SpringCloud 中使用Feign远程调用。
Provider
@RequestMapping(value = "/common-url")
@ResponseBody
public class TestController {
@GetMapping(value = "/hello")
String hello(Stirng param){
return "hello from provider :" + param;
}
}
API接口
@FeignClient(value = "spring-cloud-producer")
@RequestMapping(value = "/common-url")
@ResponseBody
public interface HelloRemote {
@GetMapping(value = "/hello")
String hello(Stirng param);
}
Consumer
@RestController
public class ConsumerController {
@Autowired
HelloRemote helloRemote;
@RequestMapping("/hello/{name}")
public String index(@PathVariable("name") String name) {
return helloRemote.hello(name);
}
}
上面是一个简单的调用,访问consumer的hello/zhangsan
会打印hello from provider : zhangsan
。
但是假如API中的testService变成了public interface HelloRemote extends TestInterface
实际调用会出现问题,调用consumer会显示:type=Internal Server Error, status=500
查看控制台发现:{"timestamp":1564244028793,"status":404,"error":"Not Found","message":"No message available","path":"/hello"}
直接报404调试发现请求的实际URL是--spring-cloud-producer/hello?name=zhangsan

为什么会这样呢?
一路追踪发现,默认解析是在org.springframework.cloud.openfeign.support.SpringMvcContract
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
//问题就在这个判断 导致没有读取公用的RequestMapping
if (clz.getInterfaces().length == 0) {
RequestMapping classAnnotation = findMergedAnnotation(clz,
RequestMapping.class);
if (classAnnotation != null) {
// Prepend path from class annotation if specified
if (classAnnotation.value().length > 0) {
String pathValue = emptyToNull(classAnnotation.value()[0]);
pathValue = resolve(pathValue);
if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().insert(0, pathValue);
}
}
}
}
这里的HelloRemote由于interface数>0所以直接忽略掉了@RequestMapping(value = "/common-url")
解决方法:自己实现一个Contract
public class CustomContract extends SpringMvcContract {
private ResourceLoader resourceLoader = new DefaultResourceLoader();
public CustomContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors) {
super(annotatedParameterProcessors);
}
public CustomContract(List<AnnotatedParameterProcessor> annotatedParameterProcessors, ConversionService
conversionService) {
super(annotatedParameterProcessors, conversionService);
}
@Override
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
//总是读取 client 的前缀
RequestMapping classAnnotation = findMergedAnnotation(clz,
RequestMapping.class);
if (classAnnotation != null) {
if (classAnnotation.value().length > 0) {
String pathValue = emptyToNull(classAnnotation.value()[0]);
pathValue = resolve(pathValue);
if (!pathValue.startsWith("/")) {
pathValue = "/" + pathValue;
}
data.template().insert(0, pathValue);
}
}
}
private String resolve(String value) {
if (StringUtils.hasText(value)
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
.resolvePlaceholders(value);
}
return value;
}
}