springboot web - 建立路由(springboot自动配置的原理)

网友投稿 565 2022-06-21


一. 测试代码

在 BookController 中, 有三个方法可以访问.

/book/add -> add()

/book/getById -> getById()

/book/getAll -> getAll()

url 和 对应的名字, 是可以不一样的, 比如 我新写个方法:

@GetMapping("byWhat")

public JsonResponse getBy(){return JsonResponse.success(null);

}

此时的对应关系就是: /book/byWhat -> getBy() 方法.

这种映射, 就是一种路由关系. 通过地址路由到方法上.

二. 建立路由

1. 配置文件配置

DispatcherServlet.properties 文件中配置了两个路由处理类:

org.springframework.web.servlet.HandlerMapping=org.`.web.servlet.handler.BeanNameUrlHandlerMapping,\

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

2. 配置类配置

spring-boot-autoconfigure 中, 有一块专门对 web 进行配置的类, WebMvcAutoConfiguration 是其中之一

3. 类图

4. SimpleUrlHandlerMapping

由于 其 祖先类  ApplicationObjectSupport 实现了 ApplicationContextAware 接口, 所以在实例化后, 会调用  setApplicationContext() 方法:

SimpleUrlHandlerMapping 重写了  initApplicationContext 方法:

在 faviconHandlerMapping() 中, 设置了 urlMap, 经过上面的方法后, 其关系为

/**/favicon.ico -> ResourceHttpRequestHandler

然后对其进行注册:

5. BeanNameUrlHandlerMapping

这个类并没有重写   initApplicationContext() 方法. 但是他的父类 AbstractDetectingUrlHandlerMapping 重写了此方法:

接着看一下  BeanNameUrlHandlerMapping 里的方法:

determineUrlsForHandler 实现了父类留的坑, 此处主要是检测 beanName 或其别名 是否是以 "/" 开头的, 如果是, 则对其执行注册方法 registerHandler(与前面4里是同一个方法).

在此例中, 并没有 beanName 是以 "/" 开头的, 所以这里并没有进行任何注册操作.

6. RequestMappingHandlerMapping

RequestMappingHandlerMapping 并不是通过 initApplicationContext() 来进行扫描触发的.

其祖先类 AbstractHandlerMethodMapping 实现了 InitializingBean 接口, 也就是说, 在属性设置后, 会调用其 afterPropertiesSet() 方法.

但是 RequestMappingHandlerMapping 重写了 afterPropertiesSet() 方法:

super.afterPropertiesSet() 调用的就是 AbstractHandlerMethodMapping 的方法了.

isHandler() 是一个过滤方法, 判断 bean 是否有 Controller 或 RequestMapping 注解:

@Override

protected boolean isHandler(Class beanType) {

return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||

AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));

}

detectHandlerMethods() 能进来的, 此例中就 bookController 了.

methods 就是 BookController 里面的那三个方法: add , getById, getAll

查找的基本思路:

1. 拿到spring容器中所有的 beanNames

2. 遍历beanNames, 进行过滤, 过滤依据: bean上是否有  Controller 或  RequestMapping 注解修饰

3. 对 bean 进行处理, 拿到他和他所有父类中的方法

4. 对这些方法进行过滤, 过滤依据为: 方法上是否有  RequestMapping 注解修饰, 并创建 RequestMappingInfo 对象 - A.

5. 为 bean 也创建 RequestMappingInfo 对象 - B.

如果 B 为空(bean上没有 RequestMappingInfo注解修饰), 则跳过合并操作

如果B不为空, 则对 A 和 B 进行合并操作. 路径 "/book/add"也就组合出来了.

这里的 mappingLookup 存放的是 RequestMappingInfo -> HandlerMethod

而 urlLookup 存放的是 url -> RequestMappingInfo

private final Map mappingLookup = new LinkedHashMap<>();

private final MultiValueMap urlLookup = new LinkedMultiValueMap<>();


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:springboot web - 启动(4) tomcat(springboot框架工作原理及流程)
下一篇:SpringBoot整合持久层技术--(一)JdbcTemplate(springboot持久层框架)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~