文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

RequestMapping要写在Controller类里吗

2023-06-19 12:29

关注

本篇内容介绍了“RequestMapping要写在Controller类里吗”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

使用Spring Cloud做项目的同学会使用Feign这个组件进行远程服务的调用,Feign这个组件采用模板的方式,有着优雅的代码书写规范。核心原理对Feign等相关注解进行解析,并提取信息,在Spring Boot工程启动时,通过反射生产Request的bean,并将提取的信息,设置到bean中,最后注入到ioc容器中。

现在有这样的场景,服务A提高RestApi接口,服务B、C、D等服务需要调用服务A提供的RestApi接口,这时最常见的做法是在服务B、C、D分别写一个FeignClient,并需要写RestApi接口的接收参数的实体和接收响应的实体DTo类。这样的做法就是需要不停复制代码。

有没有办法简洁上面的操作呢?有一种最常见的做法是将将服务A进行模块拆分,将FeignClient和常见的model、dto对外输出的类单独写一个模块,可以类似于取名a-service-open_share。这样将服务A服务分为两个模块,即A服务的业务模块和A服务需要被其他服务引用的公共类的模块。服务B、C、D只需要引用服务A的a-service-open_share就具备调用服务A的能力。

笔者在这里遇到一个有趣的其问题。首先看问题:

写一个FeignClient:

@FeignClient(name = "user-service")public interface UserClient {    @GetMapping("/users")    List<User> getUsers();

写一个实现类:

@RestControllerpublic class UserController implements UserClient {    @Autowired    UserService      userService;    @OverRide    List<User> getUsers(){       return userService.getUsers();    }

启动工程,浏览器访问接口localhost:8008/users,竟然能正确访问?!明明我在UserController类的getUsers方法没有加RequestMapping这样的注解。为何能正确的映射?!

带着这样的疑问,我进行了一番的分析和探索!

首先就是自己写了一个demo,首先创建一个接口类:

public interface ITest {    @GetMapping("/test/hi")    public String hi();}

写一个Controller类TestController

@RestControllerpublic class TestController implements ITest {    @Override    public String hi() {        return "hi you !";    }

启动工程,浏览器访问:http://localhost:8762/test/hi,浏览器显示:

hi you !

我去,TestController类的方法 hi()能够得到ITest的方法hi()的   @GetMapping(“/test/hi”)注解吗? 答案肯定是获取不到的。

特意编译了TestController字节码文件:
javap -c TestController

 public class com.example.demo.web.TestController implements com.example.demo.web.ITest {  public com.example.demo.web.TestController();    Code:       0: aload_0       1: invokespecial #1                  // Method java/lang/Object."<init>":()V       4: return  public java.lang.String hi();    Code:       0: ldc           #2                  // String hi you !       2: areturn}

上面的字节码没有任何关于@GetMapping(“/test/hi”)的信息,可见TestController直接获取不到@GetMapping(“/test/hi”)的信息。

那应该是Spring MVC在启动时在向容器注入Controller的Bean(HandlerAdapter)时做了处理。初步判断应该是通过反射获取到这些信息,并组装到Controller的Bean中。首先看通过反射能不能获取ITest的注解信息:

 public static void main(String[] args) throws ClassNotFoundException {    Class c = Class.forName("com.example.demo.web.TestController");    Class[] i=c.getInterfaces();    System.out.println("start interfaces.."  );    for(Class clz:i){        System.out.println(clz.getSimpleName());        Method[] methods = clz.getMethods();        for (Method method : methods) {            if (method.isAnnotationPresent(GetMapping.class)) {                GetMapping w = method.getAnnotation(GetMapping.class);                System.out.println("value:" + w.value()[0]  );            }        }    }    System.out.println("end interfaces.."  );    Method[] methods = c.getMethods();    for (Method method : methods) {        if (method.isAnnotationPresent(GetMapping.class)) {            GetMapping w = method.getAnnotation(GetMapping.class);            System.out.println("value:" + w.value());        }    }}

允运行上面的代码:

start interfaces..

ITest

value:/test/hi

end interfaces..

可见通过反射是TestController类是可以获取其实现的接口的注解信息的。为了验证Spring Mvc 在注入Controller的bean时通过反射获取了其实现的接口的注解信息,并作为urlMapping进行了映射。于是查看了Spring Mvc 的源码,经过一系列的跟踪在RequestMappingHandlerMapping.java类找到了以下的方法:

protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {   RequestMappingInfo info = createRequestMappingInfo(method);   if (info != null) {      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);      if (typeInfo != null) {         info = typeInfo.combine(info);      }   }   return info;}

继续跟踪源码在AnnotatedElementUtils 类的searchWithFindSemantics()方法中发现了如下代码片段:

// Search on methods in interfaces declared locallyClass<?>[] ifcs = method.getDeclaringClass().getInterfaces();result = searchOnInterfaces(method, annotationType, annotationName, containerType, processor,      visited, metaDepth, ifcs);if (result != null) {   return result;}

这就是我要寻找的代码片段,验证了我的猜测。

“RequestMapping要写在Controller类里吗”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯