FeignClient和Controller起冲突解决办法

时间:2025-04-27 12:21:39

问题描述:

在一个服务中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);
        }
    }
}