环境
spring-framework:5.1.x
spring-boot: v2.1.2.RELEASE
看一眼历史的感觉
先看一眼我们很久以前用的XML的配置方式,我举得用最原始的方式来学习会相对于简单,因为很多的配置都是显性的。我只截取最核心的部分,大概找一下感觉。
1 |
|
上面的配置基本就把一个SpringMVC的项目配置完成了,大家都了解。web.xml
是一个WEB项目的入口,而这里面就把Spring与Servlet关联起来了。
Loader1:org.springframework.web.context.ContextLoaderListener
父IOC
容器,管理所有的Bean
。
Loader2:org.springframework.web.servlet.DispatcherServlet
子IOC
容器,主要关于与WEB
相关的一些配置,比如:Controller
、HandlerMapping
等等。
这里粗略的描述一下WEB项目的一个加载顺序:listener → filter → servlet。
ContextLoaderListener
1 | org.springframework.web.context.ContextLoaderListener |
ContextLoaderListener(spring中的类)继承ContextLoader(spring中的类),并实现ServletContextListener(servlet中的接口),ServletContextListener监听ServletContext,当容器启动时,会触发ServletContextEvent事件,该事件由ServletContextListener来处理,启动初始化ServletContext时,调用contextInitialized方法。而ContextLoaderListener实现了ServletContextListener,所以,当容器启动时,触发ServletContextEvent事件,让ContextLoaderListener执行实现方法contextInitialized(ServletContextEvent sce);
1 |
|
我们细看一下我们是如何初始化一个Context
的:
1 | if (this.context == null) { |
servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
这句话实际上是优先用用户配置的,否则才会取默认的。如果我们自己配置要在哪儿配置了。对的还是要在我们的web.xml里面。
1 | <context-param> |
那我们默认的是哪个呢?
1 | static { |
是滴,有一个properties文件,里面就是默认的Context配置。
1 | org.springframework.web.context.support.XmlWebApplicationContext = |
实际上,我们默认的就是XmlWebApplicationContext
。继续扫读web.xml
的配置来加载与Spring
相关的配置。
1 | // public static final String CONFIG_LOCATION_PARAM = "contextConfigLocation"; |
调用refresh开始构建
1 | wac.refresh(); // 然而这里我觉得要单独拿一个篇章来讲Spring是如何来加载Bean。 |
DispatcherServlet
- HttpServlet 及以上部分是 Servlet 标准中提供的接口及类
- DispatcherServlet、FrameworkServlet、HttpServletBean 三者是 SpringMVC 提供的类,且后者依次分别是前者的父类。
因为是Servlet,所有会调用init来初始化。
org.springframework.web.servlet.HttpServletBean
1 | public final void init() throws ServletException { |
org.springframework.web.servlet.FrameworkServlet
1 | protected final void initServletBean() throws ServletException { |
org.springframework.web.servlet.FrameworkServlet
1 | protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { |
看到这里,我们的2个容器都是默认用的XmlWebApplicationContext
。
那问哪些HandlerMapping
、HandlerAdapter
、ViewResolver
是在哪儿加载进来的?
org.springframework.web.servlet.DispatcherServlet#onRefresh
1 | /** |
org.springframework.web.servlet.handler.AbstractHandlerMethodMapping
1 | protected void detectHandlerMethods(Object handler) { |
- 遍历Handler中的所有方法,找出其中被@RequestMapping注解标记的方法。
- 然后遍历这些方法,生成RequestMappingInfo实例。
- 将RequestMappingInfo实例以及处理器方法注册到缓存中。
org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping
1 |
|
1 | public void register(T mapping, Object handler, Method method) { |
把一些请求的映射关系放入到Map中,为后续的路由功能做数据初始化。
1 | private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>(); |
对于Request参数的一些封装&映射:
1 |
|
一般我们对关心的是一个url是如何组装的。
1 | public PatternsRequestCondition combine(PatternsRequestCondition other) { |
这是从注释上copy
下来的注解,主要有这里的pathMatcher
来组装。
1 | public String combine(String pattern1, String pattern2) { |
还是稍微的有点粗,也只描述了我们最最关心的一些点。后面再继续的对每个细节点做一个总结。
参考地址:
- https://www.jianshu.com/p/c1384f3d5698
- https://www.cnblogs.com/cyhbyw/p/8683251.html
- https://blog.csdn.net/J080624/article/details/56278461
如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。