Web接口资源是如何保存起来的?

举报
西魏陶渊明 发表于 2022/09/25 02:10:50 2022/09/25
【摘要】 # 前言 在我们使用 SpringBoot 开发中,我们定义一接口是下面这样的 @RestControllerpublic class UserController{ @GetMapping( name = "/getUserName") public String getUserName(){ ...

# 前言

在我们使用 SpringBoot 开发中,我们定义一接口是下面这样的


    
  1. @RestController
  2. public class UserController{
  3. @GetMapping( name = "/getUserName")
  4. public String getUserName(){
  5. return "Hello World";
  6. }
  7. }
1 2 3 4 5 6 7 8

这时候我们思考一个问题,我们在浏览器上只输入了一个URL地址,怎么就能访问到这个接口的呢?于是乎就引出了 今天我们要讨论的话题。Spring中的Web接口资源是如何保存起来的?

# 一、Spring中的Web接口资源是如何保存起来的?

在我们学习之前我们可以先自己来进行思考一下。处理逻辑是什么样的?

  • Spring容器解析 @RequestMapping 注解。当然这个注解又派生了其他的注解比如。

    
  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @Documented
  4. @RequestMapping(method = RequestMethod.POST)
  5. public @interface PostMapping {}
  6. @Target(ElementType.METHOD)
  7. @Retention(RetentionPolicy.RUNTIME)
  8. @Documented
  9. @RequestMapping(method = RequestMethod.PUT)
  10. public @interface PutMapping {}
  11. @Target(ElementType.METHOD)
  12. @Retention(RetentionPolicy.RUNTIME)
  13. @Documented
  14. @RequestMapping(method = RequestMethod.GET)
  15. public @interface GetMapping {}
  16. @Target(ElementType.METHOD)
  17. @Retention(RetentionPolicy.RUNTIME)
  18. @Documented
  19. @RequestMapping(method = RequestMethod.DELETE)
  20. public @interface DeleteMapping {}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
  • 我们猜测Spring源码中一定会对@RestController@Controller标记的类,里面的每个 Method进行处理,判断是否包含了上面的注解。注解那么多Spring肯定不会这样一个一个去处理。我们可以看到 上面的注解都使用了@AliasFor注解。其中奥妙就在这里。看下面例子代码。
  • 我们猜测Spring肯定对这些Method判断是否有@RequestMapping有注解。

# 1. @AliasFor使用


    
  1. @RestController
  2. public class PostController {
  3. @ApiOperation(value = "查询Bbs所有文章")
  4. @PostMapping(value = "/query/bbs/posts", produces = MediaType.APPLICATION_JSON_VALUE)
  5. public Result<PostAllResponse> queryBbsPostAll(@RequestBody PostAllSelectRequest postAllSelectRequest) {
  6. return postBiz.queryBbsPostAll(postAllSelectRequest);
  7. }
  8. public static void main(String[] args) {
  9. Method queryBbsPostAll = ClassUtils.getMethod(PostController.class, "queryBbsPostAll",PostAllSelectRequest.class);
  10. PostMapping annotation = AnnotationUtils.findAnnotation(queryBbsPostAll, PostMapping.class);
  11. ///query/bbs/posts
  12. System.out.println(StringUtils.arrayToCommaDelimitedString(annotation.value()));
  13. //application/json
  14. System.out.println(StringUtils.arrayToCommaDelimitedString(annotation.produces()));
  15. //是否包含RequestMapping: true
  16. System.out.println("是否包含RequestMapping: "+AnnotatedElementUtils.hasAnnotation(queryBbsPostAll,RequestMapping.class));
  17. RequestMapping mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(queryBbsPostAll, RequestMapping.class);
  18. ///query/bbs/posts
  19. System.out.println(StringUtils.arrayToCommaDelimitedString(mergedAnnotation.value()));
  20. }
  21. }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

可以看到只要使用下面代码就能把被@PostMapping等等的注解都涵盖了。


    
  1. System.out.println("是否包含RequestMapping: "+AnnotatedElementUtils.hasAnnotation(queryBbsPostAll,RequestMapping.class));
  2. RequestMapping mergedAnnotation = AnnotatedElementUtils.getMergedAnnotation(queryBbsPostAll, RequestMapping.class);
1 2

# 2. 解析请求Method

AbstractHandlerMethodMapping 实现 InitializingBean。在当前 Bean初始化时候会执行

afterPropertiesSet -> initHandlerMethods

从这里开始解析Web资源类的信息。请小伙伴们看下面的截图,截图中源码已经把类名也截上了,方便小伙伴们自己在根据截图看一遍源码。


    
  1. public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMapping implements InitializingBean {
  2. @Override
  3. public void afterPropertiesSet() {
  4. initHandlerMethods();
  5. }
  6. /**
  7. * Scan beans in the ApplicationContext, detect and register handler methods.
  8. * @see #getCandidateBeanNames()
  9. * @see #processCandidateBean
  10. * @see #handlerMethodsInitialized
  11. */
  12. protected void initHandlerMethods() {
  13. for (String beanName : getCandidateBeanNames()) {
  14. if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
  15. processCandidateBean(beanName);
  16. }
  17. }
  18. handlerMethodsInitialized(getHandlerMethods());
  19. }
  20. }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

RequestMappingHandlerMapping解析Method上的RequestMapping信息

isHandler 方法判断是否是web资源类。 当一个类被标记了 @Controller 或者@RequestMapping。 注意 @RestController@Controller的派生类。所以这里只用判断 @Controller 或者@RequestMapping就行了。

detectHandlerMethods方法就是真正开始解析Method的逻辑。通过解析Method上的 @RequestMapping或者其他派生的注解。生成请求信息。 注意这个请求信息里面也是有很多逻辑的不过不是本篇讨论的重点,就不说了。稍微提一下。根据规则来匹配url逻辑就在这里面。

这里我们能看到源码里拿到了Method并拿到了执行这个Method的实例Bean。在这里封装成了HandlerMethod并注册到了MappingRegistry中。

在注册的过程中把RequestMapping中的路径信息同事也放到一个urlLookup中。key是url,value是Mapping信息。

到这里其实我们就把本篇的议题就说明清楚了。下面我们在看下SpringWeb是如何将http请求信息路由到具体的HandlerMethod的吧。

# 3. 最后串一下流程

看了前面的截图,我们知道Spring是如何把这些Web资源信息给保存起来的了。然后就看是DispatcherServlet的逻辑了。

首先DispatcherServlet 是一个Servlet。Servlet相信大家都都知道就不重点说原理。 我们直接看 doService -> doDispatch 方法

根据请求路径,找到从Mapping信息,然后根据Mapping信息匹配到具体的HandlerMethod。 ok本篇内容就到这里。谢谢大家。

文章来源: springlearn.blog.csdn.net,作者:西魏陶渊明,版权归原作者所有,如需转载,请联系作者。

原文链接:springlearn.blog.csdn.net/article/details/125858106

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。