问题描述:
在一个服务中Controller和Feign接口都存在且请求路径相同,比如:
Controller定义:
@RestController
@RequestMapping("/log")
public class LogController {
@Resource
private LogService logService;
@PostMapping("/save")
public Result<Void> save(Log log) {
logService.save(log);
return ResultUtil.success();
}
}
Feign接口定义:
@FeignClient(value = "xxx-server")
@RequestMapping("/log")
public interface RemoteLogService {
@PostMapping(value = "/save")
Result<Void> save(Log log);
}
在程序启动的时候就会发现这样的报错信息
There is already ‘logController’ bean methodThere is already ‘logController’ bean method
问题分析:
SpringMVC在处理映射请求时有这样一个处理:
protected boolean isHandler(Class<?> beanType) {
return AnnotatedElementUtils.hasAnnotation(beanType, Controller.class)
|| AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class);
}
也就是说当一个类打上@Controller或者@RequestMapping注解时,就会作为请求映射,所以上面在Feign接口上打上@RequestMapping就被SpringMVC处理为了一个请求,这样就和Controller中的路径冲突报错了。
解决之法:
这里有两种解决办法,
一、不在Feign接口上使用@RequestMapping注解,写成下面这样:
@FeignClient(value = "xxx-server")
public interface RemoteLogService {
@PostMapping(value = "/log/save")
Result<Void> save(Log log);
}
或者
@FeignClient(value = "xxx-server", path = "/log")
public interface RemoteLogService {
@PostMapping(value = "/save")
Result<Void> save(Log log);
}
二、重写RequestMappingHandlerMapping方法中的 isHandler 方法
@Configuration
@ConditionalOnClass({Feign.class})
public class FeignConfiguration {
@Bean
public WebMvcRegistrations feignWebRegistrations() {
return new WebMvcRegistrationsAdapter() {
@Override
public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
return new FeignRequestMappingHandlerMapping();
}
};
}
private static class FeignRequestMappingHandlerMapping extends RequestMappingHandlerMapping {
@Override
protected boolean isHandler(Class<?> beanType) {
return super.isHandler(beanType) &&
// 如果有@FeignClient注解就不作处理
!AnnotatedElementUtils.hasAnnotation(beanType, FeignClient.class);
}
}
}