当@FeignClient遇到@RequestMapping,spring容器启动报错

在做微服务开发的时候我们常常使用openFiegn来进行远程调用,那么就会产生下面这段代码

    @FeignClient("demo-feign")
    public interface DemoFeignClient {

        @GetMapping("/test")
        void test();
    }

    @RestController
    public class DemoController implements DemoFeignClient {
        @Override
        public void test() {
            System.out.println("test");
        }
    }

我们在进行springMvc开发的时候,可以在方法上面加上@RequestMapping、@GetMapping等注解,也可以在类上面加上@RequestMapping给当前类里面所有的请求接口统一加上前缀,如下:

    @RestController
    @RequestMapping("/demo")
    public class DemoApiController implements DemoFeignClient {
        @Override
        public void test() {
            System.out.println("test");
        }
    }

但是细心的我们发现,如果做微服务开发的时候在feignClient 的类上面加上@RequestMapping,我们的程序启动就会报错,如下:

@FeignClient("demo-feign")
@RequestMapping("/demo")
public interface DemoFeignClient {
    @GetMapping("/test")
    void test();
}

@RestController
public class DemoApiController implements DemoFeignClient {
    @Override
    public void test() {
        System.out.println("test");
    }
}

错误信息如下: 

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'com.example.demofeign.DemoFeignApplication$DemoFeignClient' method 
com.example.demofeign.DemoFeignApplication$DemoFeignClient#test()
to {GET [/demo/test]}: There is already 'com.example.demofeign.DemoFeignApplication$DemoApiController' bean method
com.example.demofeign.DemoFeignApplication$DemoApiController#test() mapped.

 如果只在方法上加却不会出现这个问题,那么是什么原因导致这个报错呢。       

这个问题的产生和springMvc里面怎么判断当前类是否为controller 有关。

AbstractHandlerMethodMapping 这个类会在被spring实例化之后,获取到spring内所有的bean,然后逐个判断当前Bean是否为controller ,而判断的依据就是当前类是否有@Controller注解或者@RequestMapping注解

// org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping#isHandler
	@Override
	protected boolean isHandler(Class<?> beanType) {
		return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
				AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
	}

修复这个问题有2种方式:

1.声明了@FeignClient的接口不要再在类上面加上@RequestMapping注解了

2.创建DemoWebMvcRegistrations 类 继承RequestMappingHandlerMapping并实现WebMvcRegistrations,然后重写里面的isHandler和getRequestMappingHandlerMapping方法

@Component
public class DemoWebMvcRegistrations  implements WebMvcRegistrations {
@Override
    public RequestMappingHandlerMapping getRequestMappingHandlerMapping() {
        return new DemoRequestMappingHandlerMapping();
    }

}
/** 注意这个地方不能直接将bean 直接注入到spring 环境,
* 否则你会发现里面每一个controller 都会被映射2次
* @see org.springframework.web.servlet.handler.AbstractHandlerMethodMapping.MappingRegistry#getMappingsByUrl
**/
public class DemoRequestMappingHandlerMapping extends RequestMappingHandlerMapping implements WebMvcRegistrations {
    @Override
    protected boolean isHandler(Class<?> beanType) {
        return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
                // 当前类上存在RequestMapping 但是不存在FeignClient注解
                (AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class)
                        && !AnnotatedElementUtils.hasAnnotation(beanType, FeignClient.class)
                ));
    }

    
}

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
@FeignClient和@RequestMappingSpring框架中常用的注解,用于实现微服务之间的通信和URL映射。 @FeignClient注解用于声明一个Feign客户端接口,用于调用其他微服务的API。它需要指定要调用的微服务的名称,可以通过value或name属性指定。Feign客户端会根据接口定义自动创建代理对象,简化了与其他微服务的交互。 例如,假设有一个名为UserService的微服务,我们可以使用@FeignClient注解来声明一个与UserService交互的Feign客户端接口: ```java @FeignClient(name = "user-service") public interface UserFeignClient { @GetMapping("/users/{id}") User getUserById(@PathVariable("id") Long id); } ``` 在上面的例子中,我们声明了一个名为UserFeignClientFeign客户端接口,它与名为"user-service"的微服务进行通信。接口中定义了一个getUserById方法,用于调用"user-service"提供的获取用户信息的API。 @RequestMapping注解用于将HTTP请求映射到控制器方法上。它可以用于类级别和方法级别。在类级别上使用@RequestMapping注解可以定义共享的请求前缀,而在方法级别上使用可以定义具体的请求路径和HTTP方法。 例如,我们可以在控制器类上使用@RequestMapping注解来定义请求前缀: ```java @RestController @RequestMapping("/api/users") public class UserController { // ... } ``` 在上面的例子中,所有以"/api/users"开头的请求都会被映射到UserController类中的方法上。 在方法级别上使用@RequestMapping注解可以指定具体的请求路径和HTTP方法。例如: ```java @RestController @RequestMapping("/api/users") public class UserController { @GetMapping("/{id}") public User getUserById(@PathVariable("id") Long id) { // ... } } ``` 在上面的例子中,GET请求"/api/users/{id}"会被映射到getUserById方法上,其中{id}是一个路径变量,用于指定要获取的用户的ID。 总结一下,@FeignClient用于声明Feign客户端接口,用于调用其他微服务的API;@RequestMapping用于将HTTP请求映射到控制器方法上,可以定义请求前缀、请求路径和HTTP方法。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值